رفتار پیش‌فرض

به طور پیش‌فرض، asynq وظیفه را حداکثر 25 بار تلاش برای انجام می‌دهد. هر بار که وظیفه دوباره انجام می‌شود، از یک استراتژی تأخیر نمایی برای محاسبه تأخیر تلاش دوباره استفاده می‌کند. اگر یک وظیفه همه تلاش‌های دوباره انجام شده خود را (که به طور پیش‌فرض 25 بار است) تمام کند، وظیفه به وضعیت آرشیو شده منتقل می‌شود تا برای اهداف اشکال‌زدایی و بازرسی وظیفه، و دوباره تلاش برای اجرا نشود (هنوز می‌توانید با استفاده از CLI یا WebUI به صورت دستی وظیفه را اجرا کنید).

در ویژگی‌های دوباره انجام دستیکاری که می‌توان تنظیم کرد عبارتند از:

  • حداکثر تلاش‌های دوباره انجام برای هر وظیفه
  • فاصله زمانی برای انتظار قبل از اینکه وظیفه‌ای که ناموفق شده است، دوباره انجام شود (به عبارت دیگر، تأخیر)
  • استفاده از شمارش دوباره انجام وظیفه
  • صرف‌نظر کردن از تلاش‌ها و ارسال وظیفه به آرشیو

قسمت‌های باقیمانده این صفحه هر گزینه سفارشی مذکور بالا را توصیف می‌کنند.

سفارشی کردن تعداد حداکثر تلاش‌های دوباره انجام برای وظایف

می‌توانید حداکثر تعداد تلاش‌های دوباره انجام برای یک وظیفه را مشخص کنید وقتی که وظیفه را با استفاده از گزینه asynq.MaxRetry در صف قرار می‌دهید.

مثال:

client.Enqueue(task, asynq.MaxRetry(5))

این نشان می‌دهد که task باید حداکثر پنج بار دوباره انجام شود.

یا اگر می‌خواهید تعداد حداکثر تلاش‌های دوباره انجام برای یک وظیفه خاص را تنظیم کنید، می‌توانید آن را به عنوان گزینه پیش‌فرض برای وظیفه تنظیم کنید.

task := asynq.NewTask("feed:import", nil, asynq.MaxRetry(5))
client.Enqueue(task) // MaxRetry به 5 تنظیم شد

سفارشی کردن تأخیر دوباره انجام

می‌توانید نحوه محاسبه تأخیر دوباره انجام را با استفاده از گزینه RetryDelayFunc در ساختار Config مشخص کنید.

امضای RetryDelayFunc به شرح زیر است:

// n تعداد بارهایی که وظیفه دوباره انجام شده است
// e خطایی که توسط دستگیرنده وظیفه برگردانده شده است
// t وظیفه مربوطه
RetryDelayFunc func(n int, e error, t *asynq.Task) time.Duration

مثال:

srv := asynq.NewServer(redis, asynq.Config{
    Concurrency: 20,
    RetryDelayFunc: func(n int, e error, t *asynq.Task) time.Duration {
        return 2 * time.Second
    },
})

این نشان می‌دهد که همه وظایف ناموفق دو باره انجام شده باید قبل از پردازش دوباره، دو ثانیه منتظر بمانند.

رفتار پیش‌فرض، طبق DefaultRetryDelayFunc، استراتژی تأخیر نمایی است. مثال زیر نشان می‌دهد چگونه می‌توان برای انواع وظایف خاص تأخیر دوباره انجام را سفارشی کرد:

srv := asynq.NewServer(redis, asynq.Config{
    // برای وظیفه‌های "foo" همیشه از تأخیر 2 ثانیه‌ای استفاده شود، وظایف دیگر از رفتار پیش‌فرض استفاده می‌کنند.
    RetryDelayFunc: func(n int, e error, t *asynq.Task) time.Duration {
        if t.Type() == "foo" {
            return 2 * time.Second 
        }
        return asynq.DefaultRetryDelayFunc(n, e, t) 
    },
})

خطای غیرناموفق

گاهی اوقات ممکن است بخواهید خطایی را از دستگیرنده برگردانید و وظیفه را بعداً دوباره انجام دهید، اما بدون استفاده از شمارش دوباره انجام وظیفه. به عنوان مثال، ممکن است بخواهید بعداً دوباره تلاش شود زیرا واحد کاری دارای منابع کافی برای رسیدگی به وظیفه نیست. حین ابتدایی‌کردن سرور، می‌توانید تصمیم بگیرید یک Config برای تابع IsFailure(error) bool ارائه دهید. این تابع پیش‌فرض تعیین می‌کند که آیا خطای برگردانده‌شده از دستگیرنده به عنوان یک شکست حساب شود یا نه. اگر تابع مقدار false (یعنی خطای غیرناموفق) برگرداند، سرور از شمارش دوباره انجام وظیفه استفاده نکرده و به‌سادگی وظیفه را برای بعداً دوباره انجام زمانبندی می‌کند.

مثال:

var ErrResourceNotAvailable = errors.New("no resource is available")

func HandleResourceIntensiveTask(ctx context.Context, task *asynq.Task) error {
    if !IsResourceAvailable() {
        return ErrResourceNotAvailable
    }
    // ... منطق برای رسیدگی به وظیفه‌ی منبع‌مصرف
}

// ...

srv := asynq.NewServer(redisConnOpt, asynq.Config{
    // ... سایر گزینه‌های پیکربندی
    IsFailure: func(err error) bool {
        return err != ErrResourceNotAvailable // خطای غیرناموفق اگر منبعی در دسترس نباشد
    },
})

صرف‌نظر کردن از تلاش دوباره انجام

اگر Handler.ProcessTask یک خطای SkipRetry برگرداند، وظیفه به هر حال از تعداد دفعات تلاش دوباره انجام صرف‌نظر شده، در آرشیو ذخیره می‌شود. خطای برگردانده شده می‌تواند SkipRetry باشد یا یک خطا با SkipRetry پیچیده شده باشد.

func ExampleHandler(ctx context.Context, task *asynq.Task) error {
    // منطق برای رسیدگی به وظیفه در اینجا...
    // اگر دستگیرنده بداند که وظیفه باید دوباره انجام نشود، خطای SkipRetry را برگرداند
    return fmt.Errorf(": %w", asynq.SkipRetry)
}