Trang này mô tả cách cấu hình việc thử lại các nhiệm vụ.

Hành vi Mặc định

Theo mặc định, asynq sẽ thử lại một nhiệm vụ tối đa 25 lần. Mỗi khi nhiệm vụ được thử lại, nó sẽ sử dụng chiến lược trễ theo mô hình backoff mũ (exponential backoff) để tính toán độ trễ thử lại. Nếu một nhiệm vụ đã tiêu tốt cả số lần thử lại (mặc định là 25 lần), nó sẽ được chuyển sang trạng thái đã lưu trữ (archived) để mục đích gỡ lỗi và kiểm tra, và sẽ không được thử lại tự động nữa (bạn vẫn có thể chạy nhiệm vụ bằng cách sử dụng CLI hoặc WebUI).

Các thuộc tính thử lại nhiệm vụ sau có thể được tùy chỉnh:

  • Số lần thử lại tối đa cho mỗi nhiệm vụ
  • Khoảng thời gian chờ trước khi nhiệm vụ thất bại có thể được thử lại (tức là trễ)
  • Có sử dụng số lần thử lại của nhiệm vụ hay không
  • Có bỏ qua việc thử lại và gửi nhiệm vụ trực tiếp đến lưu trữ không

Các phần còn lại của trang này mô tả từng tùy chọn tùy chỉnh được đề cập ở trên.

Tùy chỉnh Số lần Thử lại Tối đa cho Nhiệm vụ

Bạn có thể chỉ định số lần thử lại tối đa cho một nhiệm vụ khi đưa nó vào hàng đợi bằng cách sử dụng tùy chọn asynq.MaxRetry.

Ví dụ:

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

Điều này chỉ ra rằng task nên thử lại tối đa năm lần.

Hoặc nếu bạn muốn đặt số lần thử lại tối đa cho một nhiệm vụ cụ thể, bạn có thể đặt nó là tùy chọn mặc định cho nhiệm vụ.

task := asynq.NewTask("feed:import", nil, asynq.MaxRetry(5))
client.Enqueue(task) // MaxRetry được đặt thành 5

Tùy chỉnh Trễ Thử lại

Bạn có thể chỉ định cách tính toán độ trễ thử lại bằng cách sử dụng tùy chọn RetryDelayFunc trong cấu trúc Config.

Chữ ký của RetryDelayFunc như sau:

// n là số lần nhiệm vụ đã được thử lại
// e là lỗi được trả về bởi bộ xử lý nhiệm vụ
// t là nhiệm vụ liên quan
RetryDelayFunc func(n int, e error, t *asynq.Task) time.Duration

Ví dụ:

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

Điều này chỉ ra rằng tất cả các nhiệm vụ thất bại sẽ chờ hai giây trước khi được xử lý lại.

Hành vi mặc định là mô hình backoff mũ, được định nghĩa bởi DefaultRetryDelayFunc. Ví dụ sau mô tả cách tùy chỉnh độ trễ thử lại cho các loại nhiệm vụ cụ thể:

srv := asynq.NewServer(redis, asynq.Config{
    // Đối với các nhiệm vụ "foo", luôn sử dụng độ trễ 2 giây, các nhiệm vụ khác sẽ sử dụng hành vi mặc định.
    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) 
    },
})

Lỗi Không phải Lỗi Thất bại

Đôi khi, bạn có thể muốn trả về một lỗi từ bộ xử lý và thử lại nhiệm vụ sau, nhưng không sử dụng số lần thử lại của nhiệm vụ. Ví dụ, bạn có thể muốn thử lại sau vì đơn vị công việc không có đủ tài nguyên để xử lý nhiệm vụ. Trong quá trình khởi tạo máy chủ, bạn có thể chọn cung cấp một Config cho hàm IsFailure(error) bool. Hàm dự đoán này quyết định liệu lỗi từ bộ xử lý có tính là lỗi thất bại hay không. Nếu hàm trả về giá trị false (tức là lỗi không phải lỗi thất bại), máy chủ sẽ không sử dụng số lần thử lại của nhiệm vụ và đơn giản chỉ lên lịch cho nhiệm vụ thử lại sau.

Ví dụ:

var ErrResourceNotAvailable = errors.New("không có tài nguyên khả dụng")

func HandleResourceIntensiveTask(ctx context.Context, task *asynq.Task) error {
    if !IsResourceAvailable() {
        return ErrResourceNotAvailable
    }
    // ... logic để xử lý nhiệm vụ yêu cầu tài nguyên nhiều
}

// ...

srv := asynq.NewServer(redisConnOpt, asynq.Config{
    // ... các tùy chọn cấu hình khác
    IsFailure: func(err error) bool {
        return err != ErrResourceNotAvailable // lỗi không phải lỗi thất bại nếu không có tài nguyên khả dụng
    },
})

Bỏ qua thử lại

Nếu Handler.ProcessTask trả về một lỗi SkipRetry, nhiệm vụ sẽ được lưu trữ bất kể số lần thử lại còn lại. Lỗi được trả về có thể là SkipRetry hoặc một lỗi được bao bọc bởi lỗi SkipRetry.

func ExampleHandler(ctx context.Context, task *asynq.Task) error {
    // Logic xử lý nhiệm vụ ở đây...
    // Nếu người xử lý biết rằng nhiệm vụ không nên được thử lại, trả về SkipRetry
    return fmt.Errorf(": %w", asynq.SkipRetry)
}