ما پیشنهاد می‌کنیم از ابزارهای نظارتی مانند Prometheus برای نظارت بر فرآیندها و صف‌های کاری در محیط تولید استفاده کنید.

معیارهای صف

اگر از رابط کاربری وب استفاده می کنید، می توانید با فراهم کردن دو پارامتر، ادغام با Prometheus را فعال کنید:

  • --enable-metrics-exporter: فعال‌سازی جمع‌آوری معیارهای صف و صادر کردن آن‌ها به نقطه‌پایان /metrics.
  • --prometheus-addr: فعال کردن نمایش معیارهای صف در داخل رابط کاربری وب.

صفحه معیارهای صف شبیه تصویر زیر است:

Screen Shot 2021-12-19 at 4 37 19 PM

اگر از رابط کاربری وب استفاده نمی کنید، Asynq دارای فایل دودویی است که می‌توانید اجرا نمایید تا معیارهای صف را صادر کند. همچنین یک بسته x/metrics برای جمع‌آوری معیارهای صف ارائه می‌دهد.

معیارهای فرآیند کاری

رابط Handler و ServeMux Asynq می‌تواند با معیارهایی برای قابل مشاهده مجهز گردد.

در زیر مثالی از صادر کردن معیارهای فرآیند کاری با استفاده از Prometheus آمده است. می‌توانیم کدهای خود را در برنامه به طوری که معیارهای خاص برنامه (مانند تعداد کل وظایفی که توسط فرآیند کاری پردازش شده اند) ردیابی شوند، نیز برچسب گذاری کنیم، همچنین معیارهای پیش‌فرض (مانند حافظه و پردازنده) ردیابی شده توسط Prometheus.

در زیر لیستی از معیارهای خاص برنامه که در کد مثال ردیابی شده‌اند آمده است:

  • تعداد کل وظایفی که توسط فرآیند کاری (شامل وظایف موفق و ناکام) پردازش شده‌اند.
  • تعداد وظایف ناکامی که توسط فرآیند کاری پردازش شده‌اند.
  • تعداد کنونی وظایفی که توسط فرآیند کاری در حال پردازش هستند.
package main

import (
    "context"
    "log"
    "net/http"
    "os"
    "os/signal"
    "runtime"

    "github.com/hibiken/asynq"
    "github.com/hibiken/asynq/examples/tasks"
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promauto"
    "github.com/prometheus/client_golang/prometheus/promhttp"
    "golang.org/x/sys/unix"
)

// Metric variables.
var (
    processedCounter = promauto.NewCounterVec(
        prometheus.CounterOpts{
            Name: "processed_tasks_total",
            Help: "تعداد کل وظایف پردازش شده",
        },
        []string{"task_type"},
    )

    failedCounter = promauto.NewCounterVec(
        prometheus.CounterOpts{
            Name: "failed_tasks_total",
            Help: "تعداد کل وظایف ناکام پردازش شده",
        },
        []string{"task_type"},
    )

    inProgressGauge = promauto.NewGaugeVec(
        prometheus.GaugeOpts{
            Name: "in_progress_tasks",
            Help: "تعداد کنونی وظایف در حال پردازش",
        },
        []string{"task_type"},
    )
)

func metricsMiddleware(next asynq.Handler) asynq.Handler {
    return asynq.HandlerFunc(func(ctx context.Context, t *asynq.Task) error {
        inProgressGauge.WithLabelValues(t.Type()).Inc()
        err := next.ProcessTask(ctx, t)
        inProgressGauge.WithLabelValues(t.Type()).Dec()
        if err != nil {
            failedCounter.WithLabelValues(t.Type()).Inc()
        }
        processedCounter.WithLabelValues(t.Type()).Inc()
        return err
    })
}

func main() {
    httpServeMux := http.NewServeMux()
    httpServeMux.Handle("/metrics", promhttp.Handler())
    metricsSrv := &http.Server{
        Addr:    ":2112",
        Handler: httpServeMux,
    }
    done := make(chan struct{})

    // شروع کردن سرور معیارها.
    go func() {
        err := metricsSrv.ListenAndServe()
        if err != nil && err != http.ErrServerClosed {
            log.Printf("خطا: سرور معیارها خطا داشت: %v", err)
        }
        close(done)
    }()

    srv := asynq.NewServer(
        asynq.RedisClientOpt{Addr: ":6379"},
        asynq.Config{Concurrency: 20},
    )

    mux := asynq.NewServeMux()
    mux.Use(metricsMiddleware)
    mux.HandleFunc(tasks.TypeEmail, tasks.HandleEmailTask)

    // شروع سرور کارگر.
    if err := srv.Start(mux); err != nil {
        log.Fatalf("شکست در شروع سرور کارگر: %v", err)
    }

    // منتظر ایجاد سیگنال‌ها بمانید.
    sigs := make(chan os.Signal, 1)
    signal.Notify(sigs, unix.SIGTERM, unix.SIGINT)
}