نمونه ای از پیکربندی سرور asynq برای پیاده‌سازی محدودیت نرخ پردازش وظایف

این صفحه نشان می‌دهد چگونه سرور asynq را برای پیاده‌سازی محدودیت نرخ پردازش وظایف پیکربندی کنیم.

لطفا توجه داشته باشید که این محدودیت نرخ برای هر نمونه سرور است و نه یک محدودیت نرخ سراسری.

در این مثال، ما از بسته golang.org/x/time/rate برای نمایش محدودیت نرخ استفاده خواهیم کرد. تنظیمات کلیدی در تنظیمات اولیه سرور شما IsFailure و RetryDelayFunc هستند. ما یک نوع خطای سفارشی ایجاد خواهیم کرد و از خطاهای داده شده در توابع IsFailure و RetryDelayFunc استدعا خواهیم کرد.

package main

import (
	"context"
	"errors"
	"fmt"
	"log"
	"math/rand"
	"time"

	"golang.org/x/time/rate"
	"github.com/hibiken/asynq"
)

func main() {
	srv := asynq.NewServer(
		asynq.RedisClientOpt{Addr: ":6379"},
		asynq.Config{
			Concurrency:    10,
			// اگر به محدودیت نرخ برمی‌گردد، خطا را به عنوان یک خطا شمرده نکنید.
			IsFailure:      func(err error) bool { return !IsRateLimitError(err) },
			RetryDelayFunc: retryDelay,
		},
	)

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

type RateLimitError struct {
	RetryIn time.Duration
}

func (e *RateLimitError) Error() string {
	return fmt.Sprintf("محدودیت نرخ رسیده است (تلاش مجدد در %v)", e.RetryIn)
}

func IsRateLimitError(err error) bool {
	_, ok := err.(*RateLimitError)
	return ok
}

func retryDelay(n int, err error, task *asynq.Task) time.Duration {
	var ratelimitErr *RateLimitError
	if errors.As(err, &ratelimitErr) {
		return ratelimitErr.RetryIn
	}
	return asynq.DefaultRetryDelayFunc(n, err, task)
}

// محدودیت نرخ 10 رویداد در هر ثانیه با اجازه شلیک‌های تا 30 رویداد را در نظر گرفته می‌شود.
var limiter = rate.NewLimiter(10, 30)

func handler(ctx context.Context, task *asynq.Task) error {
	if !limiter.Allow() {
		return &RateLimitError{
			RetryIn: time.Duration(rand.Intn(10)) * time.Second,
		}
	}
	log.Printf("[*] پردازش وظیفه %s", task.Payload())
	return nil
}