/// <summary> /// Stops the partition pump. In case it hasn't been started, nothing happens. /// </summary> /// /// <param name="reason">The reason why the partition pump is being closed.</param> /// /// <returns>A task to be resolved on when the operation has completed.</returns> /// private async Task StopAsync(PartitionProcessorCloseReason reason) { if (RunningTask != null) { await RunningTaskSemaphore.WaitAsync().ConfigureAwait(false); try { if (RunningTask != null) { RunningTaskTokenSource.Cancel(); RunningTaskTokenSource = null; try { await RunningTask.ConfigureAwait(false); } finally { RunningTask = null; } await InnerConsumer.CloseAsync().ConfigureAwait(false); InnerConsumer = null; await PartitionProcessor.CloseAsync(reason).ConfigureAwait(false); } } finally { RunningTaskSemaphore.Release(); } } }
/// <summary> /// Stops the partition pump. In case it isn't running, nothing happens. /// </summary> /// /// <param name="reason">The reason why the associated partition processor is being closed. In case it's <c>null</c>, the internal close reason set by this pump is used.</param> /// /// <returns>A task to be resolved on when the operation has completed.</returns> /// public async Task StopAsync(PartitionProcessorCloseReason?reason) { if (RunningTask != null) { await RunningTaskSemaphore.WaitAsync().ConfigureAwait(false); try { if (RunningTask != null) { RunningTaskTokenSource.Cancel(); RunningTaskTokenSource = null; try { // RunningTask is only expected to fail when the partition processor throws while processing // an error, but unforeseen scenarios might happen. await RunningTask.ConfigureAwait(false); } catch (Exception) { // TODO: delegate the exception handling to an Exception Callback. } RunningTask = null; // It's important to close the consumer as soon as possible. Failing to do so multiple times // would make it impossible to create more consumers for the associated partition as there's a // limit per client. await InnerConsumer.CloseAsync().ConfigureAwait(false); // In case an exception is encountered while partition processor is closing, don't catch it and // let the event processor handle it. The pump has no way to guess when a partition was lost or // when a shutdown request was sent to the event processor, so it expects a "reason" parameter to // provide this information. However, in case of pump failure, the external event processor does // not have enough information to figure out what failure reason to use, as this information is // only known by the pump. In this case, we expect the processor-provided reason to be null, and // the private CloseReason is used instead. await PartitionProcessor.CloseAsync(Context, reason ?? CloseReason).ConfigureAwait(false); } } finally { RunningTaskSemaphore.Release(); } } }