Sidekiq 이불 텀헤드 jobs
작업이 여러 이유로 실패할 수 있다는 것은 알려진 사실입니다. 예를 들어, 네트워크 장애 또는 버그 등이 있습니다. 이에 대응하기 위해, Sidekiq에는 기본적으로 대부분의 GitLab 내 작업자에 의해 기본적으로 사용되는 내장된 재시도 메커니즘이 있습니다.
작업이 실패한 후에도 해당 작업이 애플리케이션 또는 사용자에게 주요 부작용이 없이 다시 실행될 것으로 예상되므로, Sidekiq는 작업이 이듬포턴트 및 트랜잭션하도록 장려합니다.
일반적인 규칙으로, 작업자가 이듬포턴트로 간주될 수 있습니다:
- 동일한 인수로 안전하게 여러 번 실행될 수 있어야 합니다.
- 애플리케이션 부작용은 한 번만 발생할 것으로 예상됩니다 (두 번째 실행의 부작용은 영향을 미치지 않음).
그러한 예시로는 캐시 만료 작업이 있습니다.
이듬포턴트 작업에 대한 작업이 예약되면, 이미 대기열에 동일한 인수로 시작되지 않은 작업이 있다면 중복 제거됩니다.
작업자가 이듬포턴트인지 확인
다음 공유 예제를 사용하여 작업자 테스트가 통과되는지 확인하세요:
it_behaves_like 'an idempotent worker' do
it 'marks the MR as merged' do
# 이 블록 내에서 subject를 사용하면 작업이 여러 번 처리됩니다.
subject
expect(merge_request.state).to eq('merged')
end
end
작업자를 직접 perform_multiple
메서드를 사용하여 테스트하세요(job.perform
라는 이 도우미 메서드는 작업자에 자동으로 포함됩니다).
작업자를 이듬포턴트로 선언
class IdempotentWorker
include ApplicationWorker
# 작업자가 이듬포턴트로 선언되었음을 나타냅니다.
idempotent!
# ...
end
idempotent!
호출은 작업자 클래스의 가장 상위 클래스에만 있도록 권장되며,
perform
메서드가 다른 클래스 또는 모듈에 정의된 경우에도 마찬가지입니다.
작업자 클래스가 이듬포턴트로 표시되지 않았다면, 코프에서 실패합니다. 작업이 안전하게 여러 번 실행될 수 있다고 확신이 없다면 코프를 건너뜁니다.
중복 제거
이듬포턴트 작업자에 대한 작업이 대기열에 추가될 때 이미 대기열에 시작되지 않은 작업이 있는 경우, GitLab은 두 번째 작업을 삭제합니다. 첫 번째 작업을 예정한 시점에 했어야 할 일을 두 번째 작업이 실행하게 되므로 작업은 건너뜁니다.
전략
GitLab은 두 가지 중복 제거 전략을 지원합니다:
- 기본 전략은
until_executing
until_executed
더 다양한 중복 제거 전략이 제안되었습니다. 다른 전략이 필요한 작업자를 구현하고 있다면 해당 문제에 의견을 남기세요.
실행 중일 때까지
이 전략은 작업이 대기열에 추가될 때 잠금을 가져가고, 작업이 시작하기 전에 그 잠금을 제거합니다.
예를 들어, AuthorizedProjectsWorker
는 사용자 ID를 받습니다.
작업자가 실행되면 사용자의 인증을 다시 계산합니다.
GitLab은 사용자의 인증이 변경될 가능성이 있는 동작이 발생할 때마다 이 작업을 예약합니다.
동일한 사용자가 동시에 두 프로젝트에 추가되면 첫 번째 작업이 시작되기 전에 두 번째 작업이 건너뛸 수 있습니다.
첫 번째 작업이 실행될 때 양쪽 프로젝트에 대한 인증이 생성되기 때문입니다.
module AuthorizedProjectUpdate
class UserRefreshOverUserRangeWorker
include ApplicationWorker
deduplicate :until_executing
idempotent!
# ...
end
end
실행된 후까지
이 전략은 작업이 대기열에 추가될 때 잠금을 가져가고, 작업이 완료된 후에 그 잠금을 제거합니다. 이를 사용하여 한 번에 여러 번 동시에 작업이 실행되는 것을 방지할 수 있습니다.
module Ci
class BuildTraceChunkFlushWorker
include ApplicationWorker
deduplicate :until_executed
idempotent!
# ...
end
end
또한, if_deduplicated: :reschedule_once
옵션을 전달하여 현재 실행 중인 작업이 끝난 후와 한 번 중복 제거가 발생한 후에 작업을 다시 실행할 수 있습니다.
이를 통해 언제나 최신 결과가 생성되도록 보장할 수 있습니다. 자세한 내용은 이 문제를 참조하세요.
미래에 작업 예약
GitLab은 작업이 미래에 예약되어 있을 수 있다고 가정하므로 미래에 예약된 작업은 건너뛰지 않습니다.
따라서 until_executed
및 until_executing
전략 모두 미래에 예약된 작업의 중복을 제거할 수 있습니다.
미래에 예약된 작업을 중복 처리하려면 including_scheduled: true
인수를 전달하여 작업자에서 지정할 수 있습니다.
module AuthorizedProjectUpdate
class UserRefreshOverUserRangeWorker
include ApplicationWorker
deduplicate :until_executing, including_scheduled: true
idempotent!
# ...
end
end
중복 제거 TTL 설정
중복 제거는 Redis에 저장된 이듬포턴트 키에 의존합니다. 이는 일반적으로 구성된 중복 제거 전략에 따라 지워집니다.
그러나 특정 경우에는 해당 키가 해당 TTL까지 남아 있을 수 있습니다. 예를 들어 다음과 같습니다:
-
until_executing
가 사용되지만 작업이 Sidekiq 클라이언트 미들웨어를 실행한 후에도 큐에 추가되지 않았거나 실행되지 않은 경우. -
until_executed
가 사용되지만 작업이 재시도가 소진되어 완료되지 못하거나, 최대 횟수로 인해 중단되었거나, 손실되었을 때.
기본값은 6시간입니다. 이 시간 동안 첫 번째 작업이 실행되지 않았거나 완료되지 않더라도 작업이 대기열에 추가되지 않습니다.
다음과 같이 TTL을 구성할 수 있습니다:
class ProjectImportScheduleWorker
include ApplicationWorker
idempotent!
deduplicate :until_executing, ttl: 5.minutes
end
중복된 작업이 발생할 수 있으므로 이러한 사례에서만 이 TTL을 낮추도록 주의하세요.
이듬포턴트 작업을 위해 최신 WAL 위치 보존
- GitLab 14.3에서 도입.
- GitLab.com에서 활성화된 GitLab 14.4.
- Self-managed에서 활성화된 GitLab 14.6.
- GitLab 14.9에서 일반적으로 사용 가능. 피처 플래그
preserve_latest_wal_locations_for_idempotent_jobs
가 제거되었습니다.
중복 제거는 항상 최신 바이너리 복제 포인터를 고려하며, 첫 번째 포인터를 고려하지 않습니다. 이는 작업이 두 번째로 예정된 동일한 작업을 건너뛰고 Write-Ahead Log (WAL)가 손실되었기 때문에 발생합니다. 이는 이전 WAL 위치를 비교하고 뒤떨어진 복제본에서 읽는 상황을 만들 수 있습니다.
중복 제거 및 부하 분산으로 데이터 일관성을 유지하기 위해, 우리는 Redis에 이듬포턴트 작업을 위한 최신 WAL 위치를 보존하고 있습니다. 이를 통해 항상 최신 바이너리 복제 포인터를 비교하고 완전히 따라잡은 복제본에서 읽을 수 있도록 하고 있습니다.