/// <summary>
        ///   Creates and starts a new partition pump associated with the specified partition.  Partition pumps that are overwritten by the creation
        ///   of a new one are properly stopped.
        /// </summary>
        ///
        /// <param name="partitionId">The identifier of the Event Hub partition the partition pump will be associated with.  Events will be read only from this partition.</param>
        ///
        /// <returns>A task to be resolved on when the operation has completed.</returns>
        ///
        private async Task AddOrOverwritePartitionPumpAsync(string partitionId)
        {
            // Remove and stop the existing partition pump if it exists.  We are not specifying any close reason because partition
            // pumps only are overwritten in case of failure.  In these cases, the close reason is delegated to the pump as it may
            // have more information about what caused the failure.

            await RemovePartitionPumpIfItExistsAsync(partitionId).ConfigureAwait(false);

            // Create and start the new partition pump and add it to the dictionary.

            var partitionContext  = new PartitionContext(InnerClient.EventHubName, ConsumerGroup, partitionId);
            var checkpointManager = new CheckpointManager(partitionContext, Manager, Identifier);

            try
            {
                var partitionProcessor = PartitionProcessorFactory(partitionContext, checkpointManager);
                var partitionPump      = new PartitionPump(InnerClient, ConsumerGroup, partitionId, partitionProcessor, Options);

                await partitionPump.StartAsync().ConfigureAwait(false);

                PartitionPumps[partitionId] = partitionPump;
            }
            catch (Exception)
            {
                // If partition pump creation fails, we'll try again on the next time this method is called.  This should happen
                // on the next load balancing loop as long as this instance still owns the partition.
                // TODO: delegate the exception handling to an Exception Callback.
            }
        }
Exemplo n.º 2
0
        /// <summary>
        ///   The main loop of an event processor.  It loops through every owned <see cref="PartitionPump" />, checking
        ///   its status and creating a new one if necessary.
        /// </summary>
        ///
        /// <param name="cancellationToken">A <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param>
        ///
        /// <returns>A task to be resolved on when the operation has completed.</returns>
        ///
        /// <remarks>
        ///   The actual goal of this method is to perform load balancing between multiple <see cref="EventProcessor" />
        ///   instances, but this feature is currently out of the scope of the current preview.
        /// </remarks>
        ///
        private async Task RunAsync(CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                await Task.WhenAll(PartitionPumps
                                   .Where(kvp => !kvp.Value.IsRunning)
                                   .Select(async kvp =>
                {
                    try
                    {
                        await kvp.Value.StopAsync();
                    }
                    catch (Exception)
                    {
                        // We're catching every possible unhandled exception that may have happened during Partition Pump execution.
                        // TODO: delegate the exception handling to an Exception Callback.
                    }

                    var partitionId = kvp.Key;

                    var partitionContext  = new PartitionContext(InnerClient.EventHubName, ConsumerGroup, partitionId);
                    var checkpointManager = new CheckpointManager(partitionContext, Manager, Identifier);

                    var partitionProcessor = PartitionProcessorFactory(partitionContext, checkpointManager);

                    var partitionPump = new PartitionPump(InnerClient, ConsumerGroup, partitionId, partitionProcessor, Options);
                    PartitionPumps.TryUpdate(partitionId, partitionPump, partitionPump);

                    await partitionPump.StartAsync();
                })).ConfigureAwait(false);

                try
                {
                    // Wait 1 second before the next verification.

                    await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
                }
                catch (TaskCanceledException) { }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        ///   Starts the event processor.  In case it's already running, nothing happens.
        /// </summary>
        ///
        /// <returns>A task to be resolved on when the operation has completed.</returns>
        ///
        public async Task StartAsync()
        {
            if (RunningTask == null)
            {
                await RunningTaskSemaphore.WaitAsync().ConfigureAwait(false);

                try
                {
                    if (RunningTask == null)
                    {
                        RunningTaskTokenSource?.Cancel();
                        RunningTaskTokenSource = new CancellationTokenSource();

                        PartitionPumps.Clear();

                        var partitionIds = await InnerClient.GetPartitionIdsAsync().ConfigureAwait(false);

                        await Task.WhenAll(partitionIds
                                           .Select(partitionId =>
                        {
                            var partitionContext  = new PartitionContext(InnerClient.EventHubName, ConsumerGroup, partitionId);
                            var checkpointManager = new CheckpointManager(partitionContext, Manager, Identifier);

                            var partitionProcessor = PartitionProcessorFactory(partitionContext, checkpointManager);

                            var partitionPump = new PartitionPump(InnerClient, ConsumerGroup, partitionId, partitionProcessor, Options);
                            PartitionPumps.TryAdd(partitionId, partitionPump);

                            return(partitionPump.StartAsync());
                        })).ConfigureAwait(false);

                        RunningTask = RunAsync(RunningTaskTokenSource.Token);
                    }
                }
                finally
                {
                    RunningTaskSemaphore.Release();
                }
            }
        }
Exemplo n.º 4
0
        /// <summary>
        ///   Creates and starts a new partition pump associated with the specified partition.  Partition pumps that are overwritten by the creation
        ///   of a new one are properly stopped.
        /// </summary>
        ///
        /// <param name="partitionId">The identifier of the Event Hub partition the partition pump will be associated with.  Events will be read only from this partition.</param>
        /// <param name="initialSequenceNumber">The sequence number of the event within a partition where the partition pump should begin reading events.</param>
        ///
        /// <returns>A task to be resolved on when the operation has completed.</returns>
        ///
        private async Task AddOrOverwritePartitionPumpAsync(string partitionId,
                                                            long?initialSequenceNumber)
        {
            // Remove and stop the existing partition pump if it exists.  We are not specifying any close reason because partition
            // pumps only are overwritten in case of failure.  In these cases, the close reason is delegated to the pump as it may
            // have more information about what caused the failure.

            await RemovePartitionPumpIfItExistsAsync(partitionId).ConfigureAwait(false);

            // Create and start the new partition pump and add it to the dictionary.

            var partitionContext = new PartitionContext(InnerClient.FullyQualifiedNamespace, InnerClient.EventHubName, ConsumerGroup, partitionId, Identifier, Manager);

            try
            {
                BasePartitionProcessor partitionProcessor = PartitionProcessorFactory(partitionContext);
                EventProcessorOptions  options            = Options.Clone();

                // Ovewrite the initial event position in case a checkpoint exists.

                if (initialSequenceNumber.HasValue)
                {
                    options.InitialEventPosition = EventPosition.FromSequenceNumber(initialSequenceNumber.Value);
                }

                var partitionPump = new PartitionPump(InnerClient, ConsumerGroup, partitionContext, partitionProcessor, options);

                await partitionPump.StartAsync().ConfigureAwait(false);

                PartitionPumps[partitionId] = partitionPump;
            }
            catch (Exception)
            {
                // If partition pump creation fails, we'll try again on the next time this method is called.  This should happen
                // on the next load balancing loop as long as this instance still owns the partition.
                // TODO: delegate the exception handling to an Exception Callback.
            }
        }