Beispiel #1
0
        /// <summary>
        ///   Stops an owned partition processing task in case it is running.  It is also removed from the tasks dictionary
        ///   along with its corresponding token source.
        /// </summary>
        ///
        /// <param name="partitionId">The identifier of the Event Hub partition whose processing is being stopped.</param>
        /// <param name="reason">The reason why the processing for the specified partition is being stopped.</param>
        ///
        /// <returns>A task to be resolved on when the operation has completed.</returns>
        ///
        private async Task StopPartitionProcessingIfRunningAsync(string partitionId,
                                                                 ProcessingStoppedReason reason)
        {
            if (ActivePartitionProcessors.TryRemove(partitionId, out var processingTask) &&
                ActivePartitionProcessorTokenSources.TryRemove(partitionId, out var tokenSource))
            {
                try
                {
                    tokenSource.Cancel();
                    await processingTask.ConfigureAwait(false);
                }
                catch (Exception ex) when(ex is TaskCanceledException || ex is OperationCanceledException)
                {
                    // Nothing to do here.  These exceptions are expected.
                }
                catch (Exception)
                {
                    // TODO: delegate the exception handling to an Exception Callback.
                }
                finally
                {
                    tokenSource.Dispose();
                }
            }

            // TODO: if reason = Shutdown or OwnershipLost and we got an exception when closing, what should the final reason be?

            PartitionContexts.TryRemove(partitionId, out var context);
            await ProcessingForPartitionStoppedAsync(reason, context);
        }
            protected override Task OnPartitionProcessingStoppedAsync(
                EventProcessorPartition partition,
                ProcessingStoppedReason reason,
                CancellationToken cancellationToken)
            {
                try
                {
                    Console.WriteLine(
                        $"No longer processing partition { partition.PartitionId } " +
                        $"because { reason }");
                }
                catch (Exception ex)
                {
                    // It is very important that you always guard against exceptions in
                    // your handler code; the processor does not have enough
                    // understanding of your code to determine the correct action to take.
                    // Any exceptions from your handlers go uncaught by the processor and
                    // will NOT be redirected to the error handler.
                    //
                    // In this case, unhandled exceptions will not impact the processor
                    // operation but will go unobserved, hiding potential application problems.

                    Console.WriteLine($"Exception while stopping processing for a partition: { ex }");
                }

                return(Task.CompletedTask);
            }
Beispiel #3
0
 /// <summary>
 ///   Invokes the processor infrastructure method responsible for stopping a partition
 ///   processing task, using its private accessor.
 /// </summary>
 ///
 /// <typeparam name="T">The partition type to which the processor is bound.</typeparam>
 ///
 /// <param name="processor">The processor instance to operate on.</param>
 /// <param name="partitionId">The identifier of the Event Hub partition whose processing should be stopped.</param>
 /// <param name="reason">The reason why the processing is being stopped.</param>
 /// <param name="cancellationToken">A <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
 ///
 /// <returns><c>true</c> if the <paramref name="partitionId"/> was owned and was being processed; otherwise, <c>false</c>.</returns>
 ///
 private static Task <bool> InvokeTryStopProcessingPartitionAsync <T>(EventProcessor <T> processor,
                                                                      string partitionId,
                                                                      ProcessingStoppedReason reason,
                                                                      CancellationToken cancellationToken) where T : EventProcessorPartition, new() =>
 (Task <bool>)
 typeof(EventProcessor <T>)
 .GetMethod("TryStopProcessingPartitionAsync", BindingFlags.Instance | BindingFlags.NonPublic)
 .Invoke(processor, new object[] { partitionId, reason, cancellationToken });
        /// <summary>
        ///   Initializes a new instance of the <see cref="PartitionProcessingStoppedContext"/> class.
        /// </summary>
        ///
        /// <param name="partitionContext">The context of the Event Hub partition this instance is associated with.</param>
        /// <param name="reason">The reason why the processing for the associated partition is being stopped.</param>
        ///
        protected internal PartitionProcessingStoppedContext(PartitionContext partitionContext,
                                                             ProcessingStoppedReason reason)
        {
            Argument.AssertNotNull(partitionContext, nameof(partitionContext));

            Context = partitionContext;
            Reason  = reason;
        }
Beispiel #5
0
 public virtual void StopPartitionProcessingComplete(string partitionId,
                                                     ProcessingStoppedReason reason)
 {
     if (IsEnabled())
     {
         WriteEvent(21, partitionId ?? string.Empty, reason);
     }
 }
        protected override Task ProcessorStoppingAsync(ProcessingStoppedReason reason, CancellationToken cancellationToken)
        {
            var baseMessageCount = base.MessageCount;

            Interlocked.Add(ref Program.TotalMessageCount, MessageCount);

            return(base.ProcessorStoppingAsync(reason, cancellationToken));
        }
            public Task CloseAsync(EventProcessorHostPartition context, ProcessingStoppedReason reason)
            {
                // signal cancellation for any in progress executions
                _cts.Cancel();

                _logger.LogDebug(GetOperationDetails(context, $"CloseAsync, {reason.ToString()}"));
                return(Task.CompletedTask);
            }
Beispiel #8
0
        /// <summary>
        ///   Initializes a new instance of the <see cref="PartitionClosingEventArgs"/> class.
        /// </summary>
        ///
        /// <param name="partitionId">The identifier of the Event Hub partition this instance is associated with.</param>
        /// <param name="reason">The reason why the processing for the associated partition is being stopped.</param>
        /// <param name="cancellationToken">A <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        public PartitionClosingEventArgs(string partitionId,
                                         ProcessingStoppedReason reason,
                                         CancellationToken cancellationToken = default)
        {
            Argument.AssertNotNullOrEmpty(partitionId, nameof(partitionId));

            PartitionId = partitionId;
            Reason      = reason;
        }
Beispiel #9
0
        /// <summary>
        ///   Initializes a new instance of the <see cref="PartitionClosingEventArgs"/> class.
        /// </summary>
        ///
        /// <param name="partition">The context of the Event Hub partition this instance is associated with.</param>
        /// <param name="reason">The reason why the processing for the associated partition is being stopped.</param>
        /// <param name="cancellationToken">A <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        public PartitionClosingEventArgs(PartitionContext partition,
                                         ProcessingStoppedReason reason,
                                         CancellationToken cancellationToken = default)
        {
            Argument.AssertNotNull(partition, nameof(partition));

            Partition = partition;
            Reason    = reason;
        }
Beispiel #10
0
        public async Task Close(ProcessingStoppedReason stoppedReason)
        {
            _channel.Writer.Complete();

            if (stoppedReason != ProcessingStoppedReason.Shutdown)
            {
                _cancellationTokenSource.Cancel();
            }

            _shutdownTokenSource.Cancel();

            await _checkpointTask.ConfigureAwait(false);

            _cancellationTokenSource.Dispose();
            _shutdownTokenSource.Dispose();
        }
        protected sealed override async Task OnPartitionProcessingStoppedAsync(EventProcessorPartition partition, ProcessingStoppedReason reason, CancellationToken cancellationToken)
        {
            using (_logger.BeginScope("Processor Stop"))
            {
                _logger.LogInformation("Processing stopped received on partition {partitionId}", partition.PartitionId);

                if (_partitionProcessors.TryGetValue(partition.PartitionId, out var processor) && _partitionContexts.TryGetValue(partition.PartitionId, out var context))
                {
                    await processor.PartitionStopAsync(context, reason, cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    _logger.LogError("Processing stopped received on partition {partitionId}. Could not notify instance", partition.PartitionId);
                }
            }
        }
Beispiel #12
0
 /// <summary>
 ///   The handler to be called once event processing stops for a given partition.
 /// </summary>
 ///
 /// <param name="reason">The reason why the processing for the associated partition is being stopped.</param>
 /// <param name="context">The context in which the associated partition was being processed.</param>
 ///
 /// <returns>A task to be resolved on when the operation has completed.</returns>
 ///
 protected virtual ValueTask ProcessingForPartitionStoppedAsync(ProcessingStoppedReason reason,
                                                                T context) => new ValueTask();
 protected override Task OnPartitionProcessingStoppedAsync(Partition partition, ProcessingStoppedReason reason, CancellationToken cancellationToken)
 {
     return(partition.Processor.CloseAsync(partition.Context, reason));
 }
Beispiel #14
0
 protected override Task OnPartitionProcessingStoppedAsync(EventProcessorHostPartition partition, ProcessingStoppedReason reason, CancellationToken cancellationToken)
 {
     return(partition.EventProcessor.CloseAsync(partition, reason));
 }
Beispiel #15
0
        /// <inheritdoc />
        public override sealed async Task PartitionStopAsync(ProcessorPartitionContext partitionContext, ProcessingStoppedReason reason, CancellationToken cancellationToken)
        {
            await base.PartitionStopAsync(partitionContext, reason, cancellationToken).ConfigureAwait(false);

            using (Logger.BeginScope("Processor stopping"))
            {
                if (_checkpointTo == null)
                {
                    Logger.LogInformation("Shutting down but no checkpoint data available on partition {partitionId}", partitionContext.PartitionId);
                }
                else if (reason == ProcessingStoppedReason.OwnershipLost)
                {
                    Logger.LogWarning("Cannot checkpoint, ownership was lost for partition {partitionId}, last known sequence number: {checkpointTo}", partitionContext.PartitionId, _checkpointTo.SequenceNumber);
                }
                else
                {
                    try
                    {
                        Logger.LogInformation("Graceful shutdown on partition {partitionId}, forcing checkpoint to sequence number {sequenceNumber}", partitionContext.PartitionId, _checkpointTo.SequenceNumber);

                        var tokenSource       = new CancellationTokenSource(3000);
                        var checkpointSuccess = await _checkpointPolicy.CheckpointAsync(_checkpointTo, true, tokenSource.Token).ConfigureAwait(false);

                        Logger.LogInformation("Completed checkpoint on partition {partitionId} result {result}", partitionContext.PartitionId, checkpointSuccess);
                    }
                    catch (Exception e)
                    {
                        Logger.LogError(e, "Error checkpointing on partition {partitionId} during graceful shutdown, duplicate data expected", partitionContext.PartitionId);
                    }
                }

                var derivedTokenSource = new CancellationTokenSource(3000);
                await ProcessorStoppingAsync(reason, derivedTokenSource.Token).ConfigureAwait(false);
            }
        }
Beispiel #16
0
 /// <summary>
 /// Provided to allow derived types to add additional logic when the partition processor is stopping
 /// </summary>
 /// <param name="reason">The reason to stop (shutdown or lease lost)</param>
 /// <param name="cancellationToken">A token to monitor for abort and cancellation requests</param>
 protected virtual Task ProcessorStoppingAsync(ProcessingStoppedReason reason, CancellationToken cancellationToken)
 {
     return(Task.CompletedTask);
 }
Beispiel #17
0
        /// <inheritdoc />
        public virtual Task PartitionStopAsync(ProcessorPartitionContext partitionContext, ProcessingStoppedReason reason, CancellationToken cancellationToken)
        {
            using (Logger.BeginScope("OnStop"))
            {
                Logger.LogInformation("Stopping partition {partitionId}, reason {reason}", partitionContext.PartitionId, Enum.GetName(typeof(ProcessingStoppedReason), reason));

                if (reason == ProcessingStoppedReason.Shutdown)
                {
                    Logger.LogInformation("Checkpointing in graceful shutdown for partition {partitionId}", partitionContext.PartitionId, Enum.GetName(typeof(ProcessingStoppedReason), reason));
                }
            }

            return(Task.CompletedTask);
        }