Bu sayfada, Handler arayüzünün tasarımını açıklayacağım.

Sunucuya sağladığınız Handler, asenkron görev işleme mantığınızın çekirdeğidir. Handler’ın sorumluluğu, bir görevi kabul etmek ve bağlamı göz önünde bulundurarak işlemektir. İşleme başarısız olduğunda, sonraki görev yeniden denemesi için herhangi bir hatayı bildirmelidir.

Arayüz aşağıdaki gibi tanımlanmıştır:

type Handler interface {
    ProcessTask(context.Context, *Task) error
}

Bu basit bir arayüzdür ve bir Handler’ın sorumluluklarını öz olarak açıklar.

Bu işleyici arayüzünü uygulamanın çeşitli yolları vardır.

İşte görevleri işlemek için kendi struct türünüzü tanımlamanın bir örneği:

type MyTaskHandler struct {
   // ... fields
}

// ProcessTask yöntemini uygula
func (h *MyTaskHandler) ProcessTask(ctx context.Context, t *asynq.Task) error {
   // ... görev işleme mantığı
}

Hatta, HandlerFunc adaptör türü sayesinde arayüzü karşılamak için bir işlev tanımlayabilirsiniz.

func myHandler(ctx context.Context, t *asynq.Task) error {
    // ... görev işleme mantığı
}

// h, Handler arayüzünü karşılar
h := asynq.HandlerFunc(myHandler)

Çoğu durumda, giriş görevinin Type‘ını kontrol etmeniz ve buna göre işlemeniz gerekebilir.

func (h *MyTaskHandler) ProcessTask(ctx context.Context, t *asynq.Task) error {
   switch t.Type() {
   case "type1":
      // type1'i işle
   case "type2":
      // type2'yi işle
   case "typeN":
      // typeN'i işle
   default:
      return fmt.Errorf("beklenmeyen görev türü: %q", t.Type())
   }
}

Görüldüğü gibi, bir işleyici birçok farklı işleyiciden oluşabilir. Yukarıdaki örnekte her durum ayrı bir işleyici tarafından ele alınabilir. Bu, ServeMux türünün devreye girdiği yerdir.

Not: Bir işleyiciyi uygulamak için mutlaka ServeMux türünü kullanmanız gerekmez, ancak birçok durumda oldukça faydalı olabilir.
ServeMux‘u kullanarak, birden çok işleyiciyi kaydedebilirsiniz. Her görevin türünü kayıtlı desenlerle eşleştirecek ve göreve en yakın desene karşılık gelen işleyiciyi çağıracaktır.

mux := asynq.NewServeMux()
mux.Handle("email:welcome", welcomeEmailHandler) // İşleyiciyi kaydet
mux.Handle("email:reminder", reminderEmailHandler)
mux.Handle("email:", defaultEmailHandler) // "email:" ile başlayan diğer görev türleri için varsayılan işleyici

Ara Katman Kullanımı

Eğer istekleri işlemeden önce ve/veya sonra bazı kodları yürütmek istiyorsanız, bunu ara katman ile yapabilirsiniz. Ara katman, bir Handler alıp bir Handler döndüren bir işlevdir.
Aşağıda, görev işleme işleminin başlangıcını ve sonunu kaydeden bir örnek ara katman bulunmaktadır.

func loggingMiddleware(h asynq.Handler) asynq.Handler {
    return asynq.HandlerFunc(func(ctx context.Context, t *asynq.Task) error {
        start := time.Now()
        log.Printf("%q için işleme başladı", t.Type())
        err := h.ProcessTask(ctx, t)
        if err != nil {
            return err
        }
        log.Printf("%q için işleme tamamlandı: geçen süre = %v", t.Type(), time.Since(start))
        return nil
    })
}

Artık bu ara katmanı işleyicinize “sarmalayabilirsiniz”.

myHandler = loggingMiddleware(myHandler)

Ayrıca, ServeMux kullanıyorsanız, şu şekilde bir ara katman sağlayabilirsiniz.

mux := NewServeMux()
mux.Use(loggingMiddleware)

Gruplama Aracı

Eğer bir ortamda belirli bir middleware’i bir grup görevlere uygulamak istiyorsanız, bunu birden çok ServeMux örneğini birleştirerek başarabilirsiniz. Bir kısıt, her görev grubunun tip adlarında aynı önekin bulunması gerektiğidir.

Örnek:
Örneğin, siparişleri işleme ve ürünleri işleme görevleriniz varsa ve “ürün” görevlerine tümüne ve “sipariş” görevlerine başka bir ortak mantık uygulamak istiyorsanız, bunu şu şekilde yapabilirsiniz:

urunHandlers := asynq.NewServeMux()
urunHandlers.Use(urunMiddleware) // Tüm ürün görevlerine ortak mantığı uygulayın
urunHandlers.HandleFunc("urun:guncelleme", urunGuncellemeGorevIsleyici)
// ... Diğer "ürün" görev işleyicilerini kaydedin

siparisHandlers := asynq.NewServeMux()
siparisHandlers.Use(siparisMiddleware) // Tüm sipariş görevlerine ortak mantığı uygulayın
siparisHandlers.HandleFunc("siparis:iade", siparisIadeGorevIsleyici)
// ... Diğer "sipariş" görev işleyicilerini kaydedin

// Üst düzey işleyici
mux := asynq.NewServeMux()
mux.Use(someGlobalMiddleware) // Tüm görevlere ortak mantığı uygulayın
mux.Handle("urun:", urunHandlers)
mux.Handle("siparis:", siparisHandlers)

if err := srv.Run(mux); err != nil {
    log.Fatal(err)
}