Sidekiqの互換性とアップデート
Sidekiqジョブの引数は、実行スケジュール中にキューに保存されます。オンラインアップデートの間、これはいくつかの可能な状況につながる可能性があります:
- 古いバージョンのアプリケーションがジョブを発行し、アップグレードされたSidekiqノードによって実行されます。
- ジョブはアップグレード前にキューに入れられ、アップグレード後に実行されます。
- ジョブは新しいバージョンのアプリケーションを実行しているノードでキューに入れられますが、古いバージョンのアプリケーションを実行しているノードで実行されます。
新しいワーカーの追加
GitLab.comでは現在、Sidekiqのデプロイはカナリアステージでは行っていません。つまり、HTTPエンドポイントからスケジューリングできる新しいワーカーは、canaryからスケジューリングされるかもしれませんが、本番デプロイが完了するまでSidekiqでは実行されません。これはジョブのスケジューリングより数時間遅くなる可能性があります。ワーカーによっては、これは問題になりません。他のジョブ、特にレイテンシに敏感なジョブにとっては、ユーザーエクスペリエンスの低下につながります。
これは新しいワーカークラスが導入されたときにのみ適用されます。一般的な開発プロセスとして機能フラグを使うことを推奨しているので、機能フラグで変更全体(新しい Sidekiq ワーカーのスケジューリングを含む)を制御するのがベストです。
ワーカーの引数の変更
ジョブは、アプリケーションの連続するバージョン間で後方互換性と前方互換性を保つ必要があります。引数の追加や削除は、すべての Rails と Sidekiq ノードが更新されたコードを持つ前のデプロイ時に問題を引き起こす可能性があります。
引数の廃止と削除
** perform_async
およびperform
メソッドから引数を削除する前に、**引数を非推奨にします。以下の例では、perform_async
メソッドからarg2
を非推奨にし、削除しています:
-
デフォルト値 (通常は
nil
) を指定し、コメントを使用して、引数を今後のマイナーリリースで非推奨とマークします。(リリース M)class ExampleWorker # Keep arg2 parameter for backwards compatibility. def perform(object_id, arg1, arg2 = nil) # ... end end
-
1つ後のマイナーリリースで、
perform_async
の引数の使用を停止します。 (リリースM+1)ExampleWorker.perform_async(object_id, arg1)
-
次のメジャーリリースで、ワーカークラスから値を削除します。(次のメジャーリリース)
class ExampleWorker def perform(object_id, arg1) # ... end end
引数
Sidekiqワーカーに新しい引数を安全に追加するには、2つのオプションがあります:
- 新しい引数を最初にワーカーに追加するマルチステップデプロイを設定します。
- 追加の引数にはパラメータハッシュを使います。おそらくこれが最も柔軟なオプションです。
マルチステップデプロイ
このアプローチでは複数のリリースが必要です。
-
デフォルト値 (Release M) でワーカーに引数を追加してください。
class ExampleWorker def perform(object_id, new_arg = nil) # ... end end
-
Worker のすべての呼び出しに新しい引数を追加します (リリース M+1)。
ExampleWorker.perform_async(object_id, new_arg)
-
デフォルト値を削除します (リリース M+2)。
class ExampleWorker def perform(object_id, new_arg) # ... end end
パラメータ・ハッシュ
既存の Worker が既にパラメータハッシュを使用している場合、この方法では複数のリリースは必要ありません。
-
将来の柔軟性を考慮して、Worker でパラメータハッシュを使用してください。
class ExampleWorker def perform(object_id, params = {}) # ... end end
ワーカークラスの削除
ワーカークラスを削除するには、2つのマイナーリリースにわたって以下の手順に従ってください:
最初のマイナーリリースでは
-
ジョブをエンキューするコードをすべて削除しました。
たとえば、ユーザーが操作できる UI コンポーネントや API エンドポイントがあり、その結果ワーカー インスタンスがエンキューされるのであれば、それらの表面領域を削除するか、ワーカー インスタンスがエンキューされないように更新してください。
これにより、Worker クラスに関連するインスタンスがエンキューされなくなります。
- フロントエンドとバックエンドの両方のコードが、ワーカーによって行われていた作業に依存しないようにします。
-
関連する Worker クラスで、
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キュードキュメントのガイダンスに従ってRakeタスクを実行し、関連ファイルを再生成/更新してください。
-
sidekiq_remove_jobs
を使用するマイグレーション(デプロイ後のマイグレーションではない)を追加します:class RemoveMyDeprecatedWorkersJobInstances < Gitlab::Database::Migration[2.0] DEPRECATED_JOB_CLASSES = %w[ MyDeprecatedWorkerOne MyDeprecatedWorkerTwo ] # Always use `disable_ddl_transaction!` while using the `sidekiq_remove_jobs` method, as we had multiple production incidents due to `idle-in-transaction` timeout. disable_ddl_transaction! def up sidekiq_remove_jobs(job_klasses: DEPRECATED_JOB_CLASSES) end def down # This migration removes any instances of deprecated workers and cannot be undone. 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
キュー名の変更は、標準的なマイグレーションではなく、デプロイ後のマイグレーションで行う必要があります。そうしないと、これらのジョブをスケジュールするワーカーがすべて停止する前に、キューの名前が変更されてしまいます。他の例も参照してください。