メッセージ処理時間を柔軟に変更する方法
状況
Alibaba Cloud Message Service の仕様では、各メッセージのデフォルトの可視性のタイムアウトがあります。ワーカーがメッセージを受信すると、タイムアウトのカウントが開始されます。ワーカーがタイムアウト時間内にメッセージ処理を完了しない場合、メッセージは他のワーカーによって受信され処理されることがあります。
タイムアウトの利点:メッセージ処理の完了後に明示的に DeleteMessage を実行する必要があります。ワーカープロセスがクラッシュした場合でも、メッセージは別のワーカーによって処理されることが可能です。
キューのデフォルトの VisibilityTimeout を長時間に設定し、ワーカーがメッセージ処理を完了する前に、タイムアウトによりメッセージが解放されないようにするユーザーもいます。
問題
あるアプリケーションシナリオで、キューの VisibilityTimeout が 6 時間に設定されているとします。
ワーカーはメッセージ M1 を受け取ります。しかし、ワーカーがメッセージ処理を完了した後に、ワーカープロセスがクラッシュしたり、システムが再起動されたりしたとします。
メッセージ M1 は、少なくとも 6 時間が経過しない限り、別のワーカーに受信され処理されることができません。この状況は、フェールオーバーを処理するプログラムを作成するには複雑すぎます。
目的
リアルタイム要件が高く、各メッセージに迅速に対応する必要があるシナリオでは、次のことが期待されます。
キューの VisibilityTimeout を短く (例えば 5 分) すれば、現在のワーカーがクラッシュしてから最大 5 分後には、別のワーカーが処理未完了のメッセージを受信して処理できること。
ワーカーのメッセージ処理に 5 分以上かかった場合、処理中にタイムアウトしないこと。
解決策
このようなシナリオに対して、ベストプラクティスとして C# のデモを提供します (添付ファイル参照)。ワーカーがメッセージを処理している最中に、メッセージに対して ChangeVisibility が必要かどうかを定期的にチェックします。ワーカーは処理を完了した後、DeleteMessage でメッセージを削除します。
注意:
1. プログラムを実行する前に、accessId、accessKey、および endPoint を設定します。
2. 変数の説明:
- MessageMinimalLife は、メッセージが登録されたときに必要な最小生存時間を示します。メッセージが登録された時点で残っているタイムアウト時間がわずか 0.1 秒である場合、ChangeVisibility を実行してメッセージの生存時間を延ばすことはできません。したがって、MessageMinimalLife は、ChangeVisibility が実行されるまでメッセージが持続することを保証する必要があります。この変数は、サービスに応じて設定できます。
- TimerInterval は、マネージャーのタイマーの間隔を示します。メッセージが MessageMinimalLife に到達する前に、タイマーが有効になっていることを確認する必要があります。この変数を短い時間に設定できます (チェックが頻繁になります)。
- QueueMessageVisibilityTimeout は、サンプル内のメッセージのデフォルトのタイムアウト時間を示します (これはキュー内の属性です)。サンプルが ChangeVisibility を実行するたびに、VisibilityTimeout の値を QueueMessageVisibilityTimeout の値に設定します。したがって、メッセージがタイムアウトしないように、QueueMessageVisibilityTimeout の値は TimerInterval + MessageMinimalLife の値より大きくしなければなりません。
- MessageTimeout は、マネージャーのメッセージのタイムアウト時間を示します。ワーカーが立ち往生している場合、メッセージ処理は 5 時間で完了しません (この時間は通常のメッセージ処理時間をはるかに超えていると見なされます)。マネージャーはメッセージの ChangeVisibility を実行しませんが、メッセージの可視性のタイムアウトを有効にします。
3. 処理の説明
メッセージを受信した後、ワーカーはメッセージを登録し、メッセージを処理し、マネージャーの DeleteMessage を呼び出します。
最初にメッセージがマネージャーに登録されると、マネージャーは ThreadPool を呼び出して ChangeVisibilityTask をスケジュールして ChangeVisibility が必要かどうかを確認し、そのメッセージを内部メッセージリストに追加します。
マネージャーのタイマーは定期的に Parallel を呼び出して ChangeVisibilityTask を開始し、メッセージリスト内のすべてのメッセージをチェックします。
次のフローチャートに Manager.ChangeMessageVisibility (ChangeVisibilityTask) に関する処理を示します。
サンプルコードのダウンロード:ChangeMessageVisibilitySample