Exemplo n.º 1
0
        public virtual async Task ReconfigureAsync(HubConfiguration <T> configuration, CancellationToken cancellationToken)
        {
            await this.sync.WaitAsync(cancellationToken);

            try
            {
                // Cancel task.
                this.forwardingTaskCancellationTokenSource?.Cancel();

                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                // Stop routers and wait until all have finished routing.
                if (this.Configuration != null)
                {
                    Task.WaitAll(this.Configuration.Routers.Select(r => r.StopAsync(cancellationToken)).ToArray(), cancellationToken);
                }

                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                // Apply new configuration.
                this.Configuration = configuration;

                if (configuration == null)
                {
                    // Keep queue to reuse its contents when reconfiguring again.
                    this.forwardingTaskCancellationTokenSource = null;
                    this.forwardingTask = null;
                }
                else
                {
                    Task.WaitAll(this.Configuration.Routers.Select(r => r.StartAsync(cancellationToken)).ToArray(), cancellationToken);

                    // Create new queue with configured capacity while reusing left-over
                    // queue contents from previous configuration or from the
                    // not-configured state.
                    this.queue = new BlockingCollection <IQueueable>(
                        new ConcurrentQueue <IQueueable>(this.queue.ToArray() ?? Array.Empty <IQueueable>()),
                        configuration.MaximumRoutablesQueueLength);

                    var cts = new CancellationTokenSource();
                    this.forwardingTaskCancellationTokenSource = cts;

                    this.forwardingTask = new Task(() =>
                    {
                        try
                        {
                            this.processQueue(configuration, queue, cts.Token);
                        }
                        catch (OperationCanceledException)
                        {
                            throw;
                        }
                        catch
                        {
                        }
                    }, cts.Token, TaskCreationOptions.LongRunning);
                    this.forwardingTask.Start();
                }
            }
            catch
            {
                throw;
            }
            finally
            {
                this.sync.Release();
            }
        }
Exemplo n.º 2
0
        void processQueue(HubConfiguration <T> configuration, BlockingCollection <IQueueable> queue,
                          CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    var list = new List <IQueueable>();

                    // Get next routable to forward.
                    var queueable = queue.Take(cancellationToken);
                    list.Add(queueable);

                    // Get even more routables to forward within the configured time frame.
                    var tryTakeStarted = DateTime.UtcNow;
                    while ((!cancellationToken.IsCancellationRequested) &&
                           (list.Count < configuration.MaximumRoutablesForwardingCount) &&
                           (queue.TryTake(out queueable, TimeSpan.FromTicks(Math.Max(0, (tryTakeStarted.Add(configuration.WaitForMoreRoutablesForwardingDelay) - DateTime.UtcNow).Ticks)))))
                    {
                        list.Add(queueable);
                    }

                    if (cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }

                    // Apply after-enqueueing preprocessors now.
                    // TODO Test.
                    foreach (var preprocessor in configuration.Preprocessors.Where(p => !p.OnEnqueueing))
                    {
                        int i = 0;
                        while (i < list.Count)
                        {
                            var preprocessedRoutable = list[i];
                            if (preprocessedRoutable is QueueableEvent <T> queueableEvent)
                            {
                                var replacementRoutables = preprocessor.Process(queueableEvent.Event);
                                if (replacementRoutables != null)
                                {
                                    // Remove original item first.
                                    list.RemoveAt(i);

                                    if (replacementRoutables.Any())
                                    {
                                        // Insert replacement items.
                                        list.InsertRange(i, replacementRoutables.Select(r => new QueueableEvent <T>(evt: r)).ToArray());
                                        i += replacementRoutables.Count();
                                    }
                                }
                                else
                                {
                                    // Keep item.
                                    ++i;
                                }
                            }
                            else
                            {
                                // Not a routable. Keep item.
                                ++i;
                            }
                        }
                    }

                    if (cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }

                    if (list.Any())
                    {
                        foreach (var router in configuration.Routers)
                        {
                            try
                            {
                                router.ForwardAsync(list.OfType <QueueableEvent <T> >().Select(q => q.Event), default).GetAwaiter().GetResult();
                            }
                            catch
                            {
                                // TODO Log.
                            }
                        }

                        foreach (var r in list.OfType <QueueableWaitHandleSignal>())
                        {
                            try
                            {
                                r.Signal();
                            }
                            catch
                            {
                                // TODO Log.
                            }
                        }
                    }
                }
                catch (OperationCanceledException)
                {
                    return;
                }
                catch
                {
                    // TODO Log.
                }
            }
        }