GoDasturchi
Retry with Exponential Backoff

Retry with Exponential Backoff

Eksponensial kutish bilan qayta urinish

Do'stingizga qo'ng'iroq qilib, band bo'lsa nima qilasiz? Darhol qayta-qayta qo'ng'iroq qilishning o'rniga (bu — telefon tarmog'ini ham, sabringizni ham charchatadi), bir necha daqiqa kutib, keyin qayta urinasiz — va agar yana band bo'lsa, yanada ko'proq kutasiz. Exponential backoff (eksponensial kutish) — dasturdagi aynan shu odobli strategiya.

Mikroservislar tarmoq orqali gaplashgani uchun ("HTTP Service Communication" darsini eslang), so'rovlar ba'zan vaqtinchalik muvaffaqiyatsiz bo'lishi mumkin (tarmoq "g'ovuri", servis bir zumga band). Darhol qayta urinish o'rniga, HAR BIR keyingi urinishdan oldin biroz KO'PROQ kutish — vaqtinchalik muammoni hal bo'lishiga vaqt beradi, va allaqachon qiynalayotgan servisga ortiqcha yuk qo'shmaydi.

example.go
package main

import (
	"errors"
	"fmt"
	"time"
)

func retryWithBackoff(attempts int, fn func() error) error {
	var err error
	for i := 0; i < attempts; i++ {
		err = fn()
		if err == nil {
			return nil
		}
		backoff := time.Duration(1<<i) * time.Millisecond // 1ms, 2ms, 4ms, 8ms...
		time.Sleep(backoff)
	}
	return fmt.Errorf("%d urinishdan keyin muvaffaqiyatsiz: %w", attempts, err)
}

func main() {
	tries := 0
	err := retryWithBackoff(3, func() error {
		tries++
		if tries < 3 {
			return errors.New("vaqtinchalik xato")
		}
		return nil
	})
	fmt.Println(err, tries)
}

1<<i — bitni chapga siljitish ("Bytes, Runes & Sized Types" darsida ko'rgan bitli amal): i=0 bo'lganda 1, i=1da 2, i=2da 4 — har safar ikki baravar oshadi ("eksponensial"). Shuning uchun birinchi qayta urinishdan oldin 1ms, ikkinchisidan oldin 2ms, uchinchisidan oldin 4ms kutiladi. Real loyihada bu sonlar ancha kattaroq bo'ladi (masalan sekundlarda), va ko'pincha tasodifiy "jitter" (kichik tasodifiy qo'shimcha) ham qo'shiladi — bu bir vaqtda ko'plab mijoz qayta urinib, servisni yana "bosib qolishi"ning oldini oladi.

fn func() error — retry qilinadigan ISH, funksiya sifatida beriladi ("Functional Options Pattern" darsida ko'rgan "funksiyani argument sifatida berish" naqshi). Bu retryWithBackoffni har qanday ish (HTTP so'rov, baza so'rovi, fayl o'qish) uchun qayta ishlatish imkonini beradi — ish nima ekanligini bilishi shart emas, faqat uning muvaffaqiyatli yoki xatoligini biladi.

>_ Exercise

Doim muvaffaqiyatsiz bo'ladigan funksiya bilan retry'ni sinang.

  • har doim xato qaytaradigan funksiya bilan retryWithBackoff(3, ...) ni chaqiring
  • qaytgan xato matnini chop eting (3 urinishdan keyin muvaffaqiyatsiz bo'lishi kerak)

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

Exponential backoff — har bir keyingi qayta urinishdan oldin ko'proq kutish orqali, vaqtinchalik muammolarga tuzalish uchun vaqt beradi va allaqachon qiynalgan servisga ortiqcha yuk qo'shmaydi.

NEXT UP

Circuit Breaker in Services

OUTPUT

$ go run main.go
Kodingizni ishga tushiring

Retry with Exponential Backoff

Eksponensial kutish bilan qayta urinish

Do'stingizga qo'ng'iroq qilib, band bo'lsa nima qilasiz? Darhol qayta-qayta qo'ng'iroq qilishning o'rniga (bu — telefon tarmog'ini ham, sabringizni ham charchatadi), bir necha daqiqa kutib, keyin qayta urinasiz — va agar yana band bo'lsa, yanada ko'proq kutasiz. Exponential backoff (eksponensial kutish) — dasturdagi aynan shu odobli strategiya.

Mikroservislar tarmoq orqali gaplashgani uchun ("HTTP Service Communication" darsini eslang), so'rovlar ba'zan vaqtinchalik muvaffaqiyatsiz bo'lishi mumkin (tarmoq "g'ovuri", servis bir zumga band). Darhol qayta urinish o'rniga, HAR BIR keyingi urinishdan oldin biroz KO'PROQ kutish — vaqtinchalik muammoni hal bo'lishiga vaqt beradi, va allaqachon qiynalayotgan servisga ortiqcha yuk qo'shmaydi.

example.go
package main

import (
	"errors"
	"fmt"
	"time"
)

func retryWithBackoff(attempts int, fn func() error) error {
	var err error
	for i := 0; i < attempts; i++ {
		err = fn()
		if err == nil {
			return nil
		}
		backoff := time.Duration(1<<i) * time.Millisecond // 1ms, 2ms, 4ms, 8ms...
		time.Sleep(backoff)
	}
	return fmt.Errorf("%d urinishdan keyin muvaffaqiyatsiz: %w", attempts, err)
}

func main() {
	tries := 0
	err := retryWithBackoff(3, func() error {
		tries++
		if tries < 3 {
			return errors.New("vaqtinchalik xato")
		}
		return nil
	})
	fmt.Println(err, tries)
}

1<<i — bitni chapga siljitish ("Bytes, Runes & Sized Types" darsida ko'rgan bitli amal): i=0 bo'lganda 1, i=1da 2, i=2da 4 — har safar ikki baravar oshadi ("eksponensial"). Shuning uchun birinchi qayta urinishdan oldin 1ms, ikkinchisidan oldin 2ms, uchinchisidan oldin 4ms kutiladi. Real loyihada bu sonlar ancha kattaroq bo'ladi (masalan sekundlarda), va ko'pincha tasodifiy "jitter" (kichik tasodifiy qo'shimcha) ham qo'shiladi — bu bir vaqtda ko'plab mijoz qayta urinib, servisni yana "bosib qolishi"ning oldini oladi.

fn func() error — retry qilinadigan ISH, funksiya sifatida beriladi ("Functional Options Pattern" darsida ko'rgan "funksiyani argument sifatida berish" naqshi). Bu retryWithBackoffni har qanday ish (HTTP so'rov, baza so'rovi, fayl o'qish) uchun qayta ishlatish imkonini beradi — ish nima ekanligini bilishi shart emas, faqat uning muvaffaqiyatli yoki xatoligini biladi.

>_ Exercise

Doim muvaffaqiyatsiz bo'ladigan funksiya bilan retry'ni sinang.

  • har doim xato qaytaradigan funksiya bilan retryWithBackoff(3, ...) ni chaqiring
  • qaytgan xato matnini chop eting (3 urinishdan keyin muvaffaqiyatsiz bo'lishi kerak)

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

Exponential backoff — har bir keyingi qayta urinishdan oldin ko'proq kutish orqali, vaqtinchalik muammolarga tuzalish uchun vaqt beradi va allaqachon qiynalgan servisga ortiqcha yuk qo'shmaydi.

NEXT UP

Circuit Breaker in Services