사이키크 업데이트 간 호환성
사이키크 작업에 대한 인자는 실행을 위해 예약되는 동안 큐에 저장됩니다. 온라인 업데이트 중에 이는 여러 가지 가능한 상황을 초래할 수 있습니다:
- 이전 버전의 애플리케이션이 작업을 게시하고, 이는 업그레이드된 사이키크 노드에 의해 실행됩니다.
- 업그레이드 이전에 작업이 큐에 추가되지만, 업그레이드 이후에 실행됩니다.
- 새로운 버전의 애플리케이션을 실행하는 노드가 작업을 큐에 추가하지만, 이전 버전의 애플리케이션을 실행하는 노드에서 실행됩니다.
새로운 워커 추가
GitLab.com에서는 현재 카나리 단계에서 사이키크 배포가 없습니다.
이는 HTTP 엔드포인트에서 예약할 수 있는 새로운 워커가 카나리에서 예약될 수 있지만, 전체 프로덕션 배포가 완료될 때까지 사이키크에서 실행되지 않을 수 있음을 의미합니다. 이는 작업 예약보다 몇 시간 늦게 발생할 수 있습니다. 일부 워커의 경우 이는 문제가 되지 않을 것입니다. 그러나 특히 지연에 민감한 작업의 경우 이는 사용자 경험을 저하시킬 것입니다.
이것은 처음 도입될 때 새로운 워커 클래스에만 적용됩니다.
일반적인 개발 프로세스로 기능 플래그 사용을 권장하므로, 새로운 사이키크 워커의 예약을 포함한 전체 변경 사항을 기능 플래그로 제어하는 것이 가장 좋습니다.
워커의 인자 변경
작업은 애플리케이션의 연속적인 버전 간에 이전 및 이후 호환 가능해야 합니다.
인자를 추가하거나 제거하는 것은 모든 Rails 및 사이키크 노드가 업데이트된 코드를 갖기 전 배포 중에 문제가 발생할 수 있습니다.
인자를 사용 중단하고 제거하기
perform_async
및 perform
메서드에서 인자를 제거하기 전에, 이를 사용 중단하세요. 다음 예시는 perform_async
메서드에서 arg2
를 사용 중단한 후 제거하는 방법을 보여줍니다:
-
기본값(보통
nil
)을 제공하고 주석을 사용하여 오는 마이너 릴리스에서 인자가 사용 중단됨을 표시합니다. (릴리스 M)class ExampleWorker # 이전 호환성을 위해 arg2 매개변수를 유지합니다. def perform(object_id, arg1, arg2 = nil) # ... end end
-
한 마이너 릴리스 후,
perform_async
에서 인자 사용을 중단합니다. (릴리스 M+1)ExampleWorker.perform_async(object_id, arg1)
-
다음 주요 릴리스에서 워커 클래스에서 값을 제거합니다. (다음 주요 릴리스)
class ExampleWorker def perform(object_id, arg1) # ... end end
인자 추가하기
사이키크 워커에 새로운 인자를 안전하게 추가하는 방법은 두 가지가 있습니다:
다단계 배포
이 접근 방식은 여러 릴리스가 필요합니다.
-
워커에 기본값이 있는 인자를 추가합니다(릴리스 M).
class ExampleWorker def perform(object_id, new_arg = nil) # ... end end
-
워커의 모든 호출에 새로운 인자를 추가합니다(릴리스 M+1).
ExampleWorker.perform_async(object_id, new_arg)
-
기본값을 제거합니다(릴리스 M+2).
class ExampleWorker def perform(object_id, new_arg) # ... end end
파라미터 해시
이 접근 방식은 기존 작업자가 이미 파라미터 해시를 사용하는 경우 여러 릴리스를 요구하지 않습니다.
-
작업자에서 파라미터 해시를 사용하여 향후 유연성을 허용합니다.
class ExampleWorker def perform(object_id, params = {}) # ... end end
작업자 클래스 제거
작업자 클래스를 제거하려면 다음 단계를 두 개의 마이너 릴리스에 걸쳐 따릅니다.
첫 번째 마이너 릴리스에서
-
작업을 큐에 추가하는 코드를 제거합니다.
예를 들어, 사용자가 상호작용하여 작업자 인스턴스가 큐에 추가되는 UI 구성 요소나 API 엔드포인트가 있다면, 이러한 표면 영역이 제거되거나 작업자 인스턴스가 더 이상 큐에 추가되지 않도록 업데이트해야 합니다.
이렇게 하면 작업자 클래스와 관련된 인스턴스가 더 이상 큐에 추가되지 않습니다.
-
프론트엔드와 백엔드 코드가 더 이상 작업자가 수행하던 작업에 의존하지 않도록 합니다.
-
관련 작업자 클래스에서
perform
메서드의 내용을 no-op으로 교체하되, 모든 인자는 그대로 유지합니다.예를 들어, 다음
ExampleWorker
에서 작업하고 있다면:class ExampleWorker def perform(object_id) SomeService.run!(object_id) end end
no-op을 구현하는 모습은 다음과 같을 수 있습니다:
class ExampleWorker def perform(object_id); end end
이 no-op을 구현함으로써, 여전히 큐에 추가된 모든 이전 작업이 처리될 때 불필요한 사이클을 피할 수 있습니다.
이후 별도의 마이너 릴리스에서
-
작업자 클래스 파일을 삭제하고, 관련 파일을 다시 생성/업데이트하기 위해 Sidekiq 큐 문서의 지침을 따릅니다.
-
sidekiq_remove_jobs
를 사용하는 마이그레이션(배포 후 마이그레이션이 아님)을 추가합니다:class RemoveMyDeprecatedWorkersJobInstances < Gitlab::Database::Migration[2.1] DEPRECATED_JOB_CLASSES = %w[ MyDeprecatedWorkerOne MyDeprecatedWorkerTwo ] # 항상 `sidekiq_remove_jobs` 메서드를 사용할 때는 `disable_ddl_transaction!`을 사용하세요. # 여러 생산 사고가 발생했습니다. disable_ddl_transaction! def up # 작업이 `sidekiq-cron`을 통해 예약된 경우, # config/initializers/1_settings.rb에 정의된 크론 스케줄 키를 사용하여 # 예약된 작업자 세트에서 제거해야 합니다. job_to_remove = Sidekiq::Cron::Job.find('my_deprecated_worker') # 작업을 완전히 제거할 수 있습니다: job_to_remove.destroy if job_to_remove # 작업을 비활성화할 수 있습니다: job_to_remove.disable! if job_to_remove # Sidekiq 큐에서 예약된 인스턴스를 제거합니다 sidekiq_remove_jobs(job_klasses: DEPRECATED_JOB_CLASSES) end def down # 이 마이그레이션은 더 이상 사용되지 않는 작업자 인스턴스를 제거하며 되돌릴 수 없습니다. end end
큐 이름 변경
작업자를 제거하는 것과 마찬가지로, 큐 이름을 변경할 때도 주의해야 합니다.
큐 이름을 변경할 때는 배포 후 마이그레이션에서 sidekiq_queue_migrate
헬퍼 마이그레이션 메서드를 사용하세요:
class MigrateTheRenamedSidekiqQueue < Gitlab::Database::Migration[2.1]
restrict_gitlab_migration gitlab_schema: :gitlab_main
disable_ddl_transaction!
def up
sidekiq_queue_migrate 'old_queue_name', to: 'new_queue_name'
end
def down
sidekiq_queue_migrate 'new_queue_name', to: 'old_queue_name'
end
end
큐의 이름을 배포 후 마이그레이션에서 변경해야 하며, 표준 마이그레이션에서는 안 됩니다. 그렇지 않으면 작업이 이러한 작업을 예약하는 모든 작업자가 실행을 중단하기 전에 너무 일찍 실행됩니다. 추가 예시들은 이곳에서 참조하세요.
작업자 클래스 이름 변경
우리는 이것을 새로운 작업자를 추가하는 것과 유사하게 처리해야 합니다. 즉, Sidekiq 배포가 완료된 후에야 새 이름의 작업자에서 작업 스케줄링을 시작합니다.
애플리케이션의 연속 버전 간의 이전 및 이후 호환성을 보장하기 위해 다음 세 가지 마이너 릴리스를 따라 이 단계를 수행합니다:
-
새 이름의 작업자를 생성하고, 이전 작업자가 새 작업자의
#perform
메서드를 호출하도록 합니다. 새 작업자의 스케줄링을 시작할 때 제어할 기능 플래그를 도입합니다. (릴리스 M)큐에 여전히 남아 있는 이전 작업자 작업은 새 작업자에게 위임됩니다. 이 버전이 배포되면 어떤 버전의 작업이 스케줄되고 있는지, 어떤 Sidekiq가 이를 처리하는지는 더 이상 중요하지 않습니다. 이전 Sidekiq는 이전 작업자의 전체 구현을 사용하고, 새로운 Sidekiq는 새 작업자에게 위임합니다.
-
GitLab.com에 대해 기능 플래그를 활성화하고, 이후 기본적으로 활성화할 수 있도록 MR을 준비합니다. (릴리스 M+1)
-
이전 작업자 클래스를 제거하고 기능 플래그를 삭제합니다. (릴리스 M+2)