기본 동작

기본적으로 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로 설정됨

재시도 지연 사용자 정의

Config 구조체의 RetryDelayFunc 옵션을 사용하여 재시도 지연을 계산하는 방법을 지정할 수 있습니다.

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) 
    },
})

실패하지 않는 오류

가끔은 핸들러에서 오류를 반환하고 나중에 작업을 재시도하지만 작업의 재시도 횟수를 사용하지 않으려는 경우가 있습니다. 예를 들어 작업을 처리할 충분한 리소스가 없어 나중에 다시 시도하기를 원할 수 있습니다. 서버 초기화 중에 IsFailure(error) bool 함수에 대한 Config를 제공할 수 있습니다. 이 술어 함수는 핸들러에서 반환된 오류가 실패로 간주할 지 여부를 결정합니다. 함수가 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.ProcessTaskSkipRetry 오류를 반환하면 남은 재시도 횟수와 관계없이 작업이 보관됩니다. 반환된 오류는 SkipRetry 또는 SkipRetry 오류로 래핑된 오류일 수 있습니다.

func ExampleHandler(ctx context.Context, task *asynq.Task) error {
    // 여기에 작업 처리 로직이 있습니다...
    // 핸들러가 작업을 재시도해서는 안 되는 경우 SkipRetry를 반환합니다.
    return fmt.Errorf(": %w", asynq.SkipRetry)
}