Chapter 1: Go'da Tekrar Denemesine Giriş

1.1 Tekrar Deneme Mekanizmalarının İhtiyacının Anlaşılması

Birçok hesaplama senaryosunda, özellikle dağıtılmış sistemlerle veya ağ ile iletişimde bulunurken, işlemler geçici hatalar nedeniyle başarısız olabilir. Bu hatalar genellikle ağ kararsızlığı, bir hizmetin kısa süreli kullanılamaması veya zaman aşımı gibi geçici sorunlardır. Hemen başarısız olmak yerine, sistemler geçici hatalarla karşılaşan işlemleri tekrar denemek üzere tasarlanmalıdır. Bu yaklaşım, güvenilirlik ve dayanıklılığı artırır.

Tekrar deneme mekanizmaları, işlemlerin tutarlılığı ve tamamlanması gereken uygulamalarda önemli olabilir. Ayrıca, son kullanıcıların deneyimlediği hata oranını azaltabilirler. Ancak, tekrar deneme mekanizmasını uygulamak, ne sıklıkla ve ne kadar süreyle tekrar deneneceğine karar verme gibi zorluklarla birlikte gelir. İşte burada, geri çekilme stratejileri önemli bir rol oynar.

1.2 go-retry Kütüphanesinin Genel Bakışı

Go'daki go-retry kütüphanesi, çeşitli geri çekilme stratejileri ile uygulamalarınıza tekrarlama mantığı eklemenin esnek bir yolunu sağlar. Temel özellikler şunları içerir:

  • Genişletilebilirlik: Go'nun http paketi gibi, go-retry genişletilebilir olacak şekilde tasarlanmıştır. Kendi geri çekilme işlevlerinizi yazabilir veya sağlanan kullanışlı filtrelerden yararlanabilirsiniz.
  • Bağımsızlık: Kütüphane, yalnızca Go standart kitaplığına dayanır ve dış bağımlılıklardan kaçınarak projenizi hafif tutar.
  • Eşzamanlılık: Eşzamanlı kullanım için güvenlidir ve herhangi ekstra zahmet olmaksızın gorutinlerle çalışabilir.
  • Bağlam odaklı: Zaman aşımı ve iptal için Go'nun yerel bağlamlarını destekler ve Go'nun eşzamanlılık modeliyle sorunsuz entegre olur.

Chapter 2: Kütüphanelerin İçe Aktarılması

go-retry kütüphanesini kullanmadan önce, projenize içe aktarılması gerekmektedir. Bunun için, modülünüze bağımlılıkları eklemek için Go komutu olan go get kullanılabilir. Basitçe terminalinizi açın ve şunu çalıştırın:

go get github.com/sethvargo/go-retry

Bu komut, go-retry kütüphanesini alacak ve projenizin bağımlılıklarına ekleyecektir. Bundan sonra, kodunuzu diğer herhangi bir Go paketi gibi içe aktarabilirsiniz.

Chapter 3: Temel Tekrar Deneme Mantığının Uygulanması

3.1 Sabit Geri Çekilme ile Basit Tekrar Deneme

En basit tekrarlama mantığı, her tekrar deneme arasında sabit bir süre beklemeyi içerir. go-retry ile sabit geri çekilme kullanarak tekrar denemeleri gerçekleştirebilirsiniz.

İşte go-retry ile sabit geri çekilme kullanımı örneği:

package main

import (
  "context"
  "time"
  "github.com/sethvargo/go-retry"
)

func main() {
  ctx := context.Background()

  // Yeni sabit geri çekilme oluştur
  backoff := retry.NewConstant(1 * time.Second)

  // Tekrar deneme mantığını, retry.Do'ya iletilen bir işlev içinde sarmalayın
  operation := func(ctx context.Context) error {
    // Kodunuz burada. Tekrar denemek için retry.RetryableError(err) veya durdurmak için nil döndürün.
    // Örnek:
    // err := someOperation()
    // if err != nil {
    //   return retry.RetryableError(err)
    // }
    // return nil

    return nil
  }

  // İstenen bağlam, geri çekilme stratejisi ve işlemle retry.Do kullanın
  if err := retry.Do(ctx, backoff, operation); err != nil {
    // Hata ile başa çıkın
  }
}

Bu örnekte, retry.Do işlevi, başarılı olana kadar veya bağlam zaman aşımına uğrayana veya iptal edilene kadar operation işlevini her 1 saniyede bir deneyecektir.

3.2 Üstel Geri Çekilme Uygulama

Üstel geri çekilme, tekrar denemeler arasındaki bekleme süresini üstel olarak artırır. Bu strateji, sisteme yükü azaltmaya yardımcı olur ve özellikle büyük ölçekli sistemler veya bulut hizmetleri ile uğraşırken çok yararlıdır.

go-retry ile üstel geri çekilmenin nasıl kullanılacağı aşağıdaki gibidir:

package main

import (
  "context"
  "time"
  "github.com/sethvargo/go-retry"
)

func main() {
  ctx := context.Background()

  // Yeni üstel geri çekilme oluştur
  backoff := retry.NewExponential(1 * time.Second)

  // Tekrar denenebilir işlemi sağlayın
  operation := func(ctx context.Context) error {
    // Önceki gösterildiği gibi işlemi uygulayın
    return nil
  }

  // Üstel geri çekilme ile işlemi gerçekleştirmek için retry.Do kullanın
  if err := retry.Do(ctx, backoff, operation); err != nil {
    // Hata ile başa çıkın
  }
}

Üstel geri çekilmede, başlangıç geri çekilme 1 saniye olarak ayarlanmışsa, tekrar denemeler 1sn, 2sn, 4sn vs. şeklinde, üstel olarak artan bir bekleme süresine sahip olacaktır.

3.3 Fibonacci Geri Çekilme Stratejisi

Fibonacci geri çekilme stratejisi, yeniden denemeler arasındaki bekleme süresini belirlemek için Fibonacci dizisini kullanır; bu, aşamalı olarak artan bir zaman aşımının faydalı olduğu ağ ile ilgili sorunlar için iyi bir strateji olabilir.

go-retry ile Fibonacci geri çekilmesinin uygulanması aşağıda gösterilmiştir:

package main

import (
  "context"
  "time"
  "github.com/sethvargo/go-retry"
)

func main() {
    ctx := context.Background()

    // Yeni bir Fibonacci geri çekilme oluştur
    geriÇekilme := retry.NewFibonacci(1 * time.Second)

    // Yeniden denenecek bir işlemi tanımla
    işlem := func(ctx context.Context) error {
        // Burada, başarısız olabilecek ve yeniden denemeye ihtiyaç duyan eylemi gerçekleştirme mantığı olacaktı
        return nil
    }
    
    // Fibonacci geri çekilme ile işlemi yeniden dene ve retry.Do kullan
    if err := retry.Do(ctx, geriÇekilme, işlem); err != nil {
        // Hata ile başa çık
    }
}

Başlangıç değeri 1 saniye olan Fibonacci geri çekilme ile, yeniden denemeler Fibonacci dizisini takip ederek 1s, 1s, 2s, 3s, 5s vb. sonrasında gerçekleşecektir.

Bölüm 4: Gelişmiş Yeniden Deneme Teknikleri ve Aracı Yazılımları

4.1 Yeniden Denemelerde Jitter Kullanımı

Yeniden deneme mantığını uygularken, sistem üzerinde eş zamanlı yeniden denemelerin etkisini göz önünde bulundurmak önemlidir; bu durum, bir yıldırım sürüsü problemine yol açabilir. Bu sorunu hafifletmek için, geri çekilme aralıklarına rastgele jitter ekleyebiliriz. Bu teknik, yeniden deneme girişimlerini zamanlamak için yardımcı olur ve birden fazla istemcinin aynı anda yeniden denemede bulunma olasılığını azaltır.

Jitter eklemenin bir örneği:

b := retry.NewFibonacci(1 * time.Second)

// Bir sonraki değeri, +/- 500ms olarak döndür
b = retry.WithJitter(500 * time.Millisecond, b)

// Bir sonraki değeri, sonucun %5'i kadar +/- döndür
b = retry.WithJitterPercent(5, b)

4.2 Maksimum Yeniden Deneme Sayısının Belirlenmesi

Bazı senaryolarda, uzun ve etkisiz yeniden denemeleri engellemek için yeniden deneme girişimlerinin sayısını sınırlandırmak gereklidir. Maksimum yeniden deneme sayısını belirterek, işlemden vazgeçmeden önce deneme sayısını kontrol altına alabiliriz.

Maksimum yeniden deneme belirleme örneği:

b := retry.NewFibonacci(1 * time.Second)

// 5. deneme başarısız olduğunda, 4 yeniden deneme sonunda dur
b = retry.WithMaxRetries(4, b)

4.3 Bireysel Geri Çekilme Sürelerinin Sınırlanması

Bireysel geri çekilme sürelerinin belirli bir eşiği aşmamasını sağlamak için CappedDuration aracı yazılımını kullanabiliriz. Bu, aşırı derecede uzun geri çekilme aralıklarının hesaplanmasını önler ve yeniden deneme davranışına öngörülebilirlik katar.

Bireysel geri çekilme sürelerinin sınırlanması örneği:

b := retry.NewFibonacci(1 * time.Second)

// Maksimum değerin 2 saniye olmasını sağla
b = retry.WithCappedDuration(2 * time.Second, b)

4.4 Toplam Yeniden Deneme Süresinin Kontrolü

Tüm yeniden deneme süreci için belirli bir süre sınırı olması gereken senaryolarda, toplam yürütme süresi için WithMaxDuration aracı yazılımını kullanarak maksimum toplam yürütme süresini belirleyebiliriz. Bu, yeniden deneme sürecinin sonsuzca devam etmemesini sağlayarak, yeniden denemelere bir süre bütçesi uygular.

Toplam yeniden deneme süresinin kontrolü örneği:

b := retry.NewFibonacci(1 * time.Second)

// Maksimum toplam yeniden deneme süresi 5 saniye olacak şekilde ayarla
b = retry.WithMaxDuration(5 * time.Second, b)