/// <summary>
        /// <see cref="DirectSequentialProcessor{TInput}"/>
        /// </summary>
        /// <param name="circuitBreakerPolicy"><see cref="CircuitBreakerPolicy"/></param>
        /// <param name="clusterOptions"><see cref="ClusterOptions"/></param>
        /// <param name="progress">Progress of the current bulk</param>
        /// <param name="cts"><see cref="CancellationTokenSource"/></param>
        /// <param name="logger"><see cref="ILogger"/></param>
        protected DirectSequentialProcessor(AsyncCircuitBreakerPolicy circuitBreakerPolicy,
                                            ClusterOptions clusterOptions,
                                            IProgress <double> progress,
                                            CancellationTokenSource cts,
                                            ILogger logger) : base(circuitBreakerPolicy, clusterOptions, logger)
        {
            ItemsSubjectSubscription = SynchronizedItemsSubject
                                       .ObserveOn(new EventLoopScheduler(ts => new Thread(ts)
            {
                IsBackground = true, Priority = ThreadPriority
            }))
                                       .Select(item =>
            {
                return(Observable.FromAsync(() =>
                {
                    return CircuitBreakerPolicy.ExecuteAndCaptureAsync(
                        ct => Process(item, progress, ct), cts.Token);
                }));
            })
                                       // Dequeue sequentially
                                       .Concat()
                                       .Subscribe(unit =>
            {
                if (unit.Outcome == OutcomeType.Failure)
                {
                    Logger.LogCritical(
                        unit.FinalException != null
                                    ? $"Could not process item: {unit.FinalException.Message}."
                                    : "An error has occured while processing the item.");
                }
            },
                                                  ex => Logger.LogError(ex.Message));

            ItemsExecutorSubjectSubscription = SynchronizedItemsExecutorSubject
                                               .ObserveOn(new EventLoopScheduler(ts => new Thread(ts)
            {
                IsBackground = true, Priority = ThreadPriority
            }))
                                               .Select(item =>
            {
                return(Observable.FromAsync(() =>
                {
                    return CircuitBreakerPolicy.ExecuteAndCaptureAsync(
                        ct => Process(item, progress, ct), cts.Token);
                }));
            })
                                               // Dequeue sequentially
                                               .Concat()
                                               .Subscribe(unit =>
            {
                if (unit.Outcome == OutcomeType.Failure)
                {
                    Logger.LogCritical(
                        unit.FinalException != null
                                    ? $"Could not process item: {unit.FinalException.Message}."
                                    : "An error has occured while processing the item.");
                }
            },
                                                          ex => Logger.LogError(ex.Message));
        }
Example #2
0
 /// <summary>
 /// <see cref="AsyncProcessor{TInput,TOutput,TAsync}"/>
 /// </summary>
 /// <param name="circuitBreakerPolicy"><see cref="CircuitBreakerPolicy"/></param>
 /// <param name="clusterOptions"><see cref="ClusterOptions"/></param>
 /// <param name="cts"><see cref="CancellationTokenSource"/></param>
 /// <param name="logger"><see cref="ILogger"/></param>
 protected AsyncProcessor(AsyncCircuitBreakerPolicy circuitBreakerPolicy,
                          ClusterOptions clusterOptions,
                          CancellationTokenSource cts,
                          ILogger logger) : base(circuitBreakerPolicy, clusterOptions, logger)
 {
     // We observe new items on an EventLoopScheduler which is backed by a dedicated background thread
     // Then we process items asynchronously, with a circuit breaker policy
     ItemsSubjectSubscription = SynchronizedItemsSubject
                                .ObserveOn(new EventLoopScheduler(ts => new Thread(ts)
     {
         IsBackground = true, Priority = ThreadPriority
     }))
                                .Select(item =>
     {
         return(Observable.FromAsync(() =>
         {
             // ExecuteAndCaptureAsync let items to be "captured" in a way they never throw any exception, but are gracefully handled by a circuit breaker policy on non-success attempt
             return CircuitBreakerPolicy.ExecuteAndCaptureAsync(
                 ct => Process(item, ct), cts.Token);
         }));
     })
                                .Merge()
                                .Subscribe(unit =>
     {
         if (unit.Outcome == OutcomeType.Failure)
         {
             Logger.LogCritical(
                 unit.FinalException != null
                             ? $"Could not process bulk: {unit.FinalException.Message}."
                             : "An error has occured while processing the bulk.");
         }
     },
                                           ex => Logger.LogError(ex.Message));
 }
Example #3
0
 /// <summary>
 /// Process an incoming item
 /// </summary>
 /// <param name="item"><see cref="AsyncItem{TInput,TOutput}"/></param>
 protected Task <TOutput> ProcessAsync(TAsync item)
 {
     Interlocked.Increment(ref _totalItemsProcessed);
     item.CancellationToken.Register(() => { item.TaskCompletionSource.TrySetCanceled(); });
     SynchronizedItemsSubject.OnNext(item);
     return(item.TaskCompletionSource.Task);
 }
Example #4
0
 /// <summary>
 /// <see cref="AsyncParallelProcessor{TInput,TOutput,TAsync}"/>
 /// </summary>
 /// <param name="circuitBreakerPolicy"><see cref="CircuitBreakerPolicy"/></param>
 /// <param name="clusterOptions"><see cref="ClusterOptions"/></param>
 /// <param name="progress">Progress of the current bulk</param>
 /// <param name="cts"><see cref="CancellationTokenSource"/></param>
 /// <param name="logger"><see cref="ILogger"/></param>
 protected AsyncParallelProcessor(AsyncCircuitBreakerPolicy circuitBreakerPolicy,
                                  ClusterOptions clusterOptions,
                                  IProgress <double> progress,
                                  CancellationTokenSource cts,
                                  ILogger logger) : base(circuitBreakerPolicy, clusterOptions, logger)
 {
     // We observe new items on an EventLoopScheduler which is backed by a dedicated background thread
     // Then we limit number of items to be processed by a sliding window
     // Then we process items asynchronously, with a circuit breaker policy
     ItemsSubjectSubscription = SynchronizedItemsSubject
                                .ObserveOn(new EventLoopScheduler(ts => new Thread(ts)
     {
         IsBackground = true, Priority = ThreadPriority
     }))
                                .Limit(() => ClusterOptions.NodeThrottling,
                                       ClusterOptions.Window,
                                       TaskPoolScheduler.Default,
                                       ItemsBuffer,
                                       ClusterOptions.EvictItemsWhenNodesAreFull,
                                       EvictedItemsSubject,
                                       Logger)
                                .Select(batch =>
     {
         return(Observable.FromAsync(() =>
         {
             // ExecuteAndCaptureAsync let items to be "captured" in a way they never throw any exception, but are gracefully handled by a circuit breaker policy on non-success attempt
             return CircuitBreakerPolicy.ExecuteAndCaptureAsync(
                 ct => Process(batch.ToList(), progress, ct), cts.Token);
         }));
     })
                                // Dequeue in parallel
                                .Merge()
                                .Subscribe(unit =>
     {
         if (unit.Outcome == OutcomeType.Failure)
         {
             Logger.LogCritical(
                 unit.FinalException != null
                             ? $"Could not process bulk: {unit.FinalException.Message}."
                             : "An error has occured while processing the bulk.");
         }
     },
                                           ex => Logger.LogError(ex.Message));
 }