アプリケーションは、.NET 4.6.1と Microsoft.Azure.ServiceBus.EventProcessorHost nugetパッケージv2.0.2 を、その依存関係 WindowsAzure.ServiceBusパッケージv3.0.1 とともに使用して処理します。 Azure EventHubメッセージ。
アプリケーションにはIEventProcessor
の実装があります。未処理の例外がProcessEventsAsync
メソッドからスローされた場合、EventProcessorHost
はそれらのメッセージを実行中のIEventProcessor
のインスタンスに再送信しません。 (逸話的に、ホスティングアプリケーションが停止して再起動した場合、またはリースが失われて再取得された場合は、再送信されます。)
例外が発生したイベントメッセージをEventProcessorHost
によってIEventProcessor
実装に強制的に再送信する方法はありますか?
考えられる解決策の1つは、ほぼ同じ質問に対するこのコメントで示されています。 IEventProcessor.ProcessEventsAsyncで未処理のEventHubメッセージを再配信する
コメントは、最後に正常に処理されたイベントメッセージのコピーを保持し、ProcessEventsAsync
で例外が発生したときにそのメッセージを使用して明示的にチェックポイントを設定することを提案しています。ただし、そのようなソリューションを実装してテストした後でも、EventProcessorHost
は再送信されません。実装は非常に簡単です。
private EventData _lastSuccessfulEvent;
public async Task ProcessEventsAsync(
PartitionContext context,
IEnumerable<EventData> messages)
{
try
{
await ProcessEvents(context, messages); // does actual processing, may throw exception
_lastSuccessfulEvent = messages
.OrderByDescending(ed => ed.SequenceNumber)
.First();
}
catch(Exception ex)
{
await context.CheckpointAsync(_lastSuccessfulEvent);
}
}
部分的なログサンプルはこちらから入手できます: https://Gist.github.com/ttbjj/4781aa992941e00e4e15e0bf1c45f316#file-gistfile1-txt
[〜#〜] tldr [〜#〜]:失敗したバッチを再生する唯一の信頼できる方法 _IEventProcessor.ProcessEventsAsync
_へのイベントの数は-Shutdown
EventProcessorHost
(別名EPH
)すぐに-eph.UnregisterEventProcessorAsync()
または プロセスの終了 -状況に応じて。これにより、他のEPH
インスタンスがこのパーティションのリースを取得し、前のチェックポイントから開始できるようになります。
これを説明する前に-私はそれを強調したいのですが、これは素晴らしい質問であり、実際、私たちがしなければならなかった最も難しい設計上の選択の1つでしたEPH
。私の見解では、それはusability
フレームワークのsupportability
/EPH
と_Technical-Correctness
_のトレードオフでした。
理想的な状況は次のようになります:_IEventProcessorImpl.ProcessEventsAsync
_のユーザーコードが例外をスローした場合-EPH
ライブラリはキャッチすべきではありませんこの。このException
-プロセスをクラッシュさせ、_crash-dump
_はcallstack
の責任を明確に示しているはずです。私はまだ信じています-これは最も_technically-correct
_の解決策です。
現在の状況:_IEventProcessorImpl.ProcessEventsAsync
_ APIとEPH
の契約は、
EventData
がEventHubsサービスから受信できる限り-_IEventProcessorImplementation.ProcessEventsAsync
_でユーザーコールバック(_EventData's
_)を呼び出し続けます。ユーザーコールバックは、呼び出し中にエラーをスローします。_EventProcessorOptions.ExceptionReceived
_に通知してください。IEventProcessorImpl.ProcessEventsAsync
_内のユーザーコードはすべてのエラーを処理し、必要に応じて_Retry's
_を組み込む必要があります。 EPH
は、ユーザーが処理時間を完全に制御できるようにするために、このコールバックにタイムアウトを設定しません。EventData
に特別なプロパティをマークします-ex:type = _poison-event
_の場合、同じEventHub
に再送信します(ポインタを含めます)実際のイベントに、これらの_EventData.Offset
_とSequenceNumber
を新しい_EventData.ApplicationProperties
_)にコピーするか、SERVICEBUSキューに転送するか、基本的にpoison-eventの処理を特定して延期します。Exceptions
に遭遇している場合は、この例外を除いて、プロセスをキャッチしてEPH
またはfailfast
をシャットダウンします。 EPH
が戻ってくると、そこから始まります。「古いイベント」のチェックポイントが機能しないのはなぜですか(EPH
を一般的に理解するには this を読んでください)::
舞台裏では、EPH
はEventHubConsumergroupパーティションのレシーバーごとにポンプを実行しています。そのジョブは、指定されたcheckpoint
(存在する場合)からレシーバーを起動し、IEventProcessor
実装し、チェックポイント内の指定されたreceive
から指定されたEventHubパーティションからOffset
(存在しない場合-_EventProcessorOptions.initialOffsetProvider
_)、最終的に_IEventProcessorImpl.ProcessEventsAsync
_を呼び出します。 Checkpoint
の目的は、EPH
プロセスがシャットダウンし、パーティションの所有権が別のEPH
インスタンスに移動したときに、メッセージの処理を確実に開始できるようにすることです。したがって、checkpoint
は[〜#〜] pump [〜#〜]の開始時にのみ消費され、[ポンプが始動すると、〜#〜] not [〜#〜]が読み取られます。
私がこれを書いているとき、EPH
はバージョン 2.2.1 です。