/// <inheritdoc />
 public Task HandleAsync <T>(IWorkGroup workGroup, IReceivedMessage <T> message, IWorkerNotification notifications, Action <IReceivedMessage <T>, IWorkerNotification> functionToRun, ITaskFactory taskFactory) where T : class
 {
     using (IScope scope = _tracer.BuildSpan("SchedulerMessageHandler").StartActive(finishSpanOnDispose: true))
     {
         return(_handler.HandleAsync(workGroup, message, notifications, functionToRun, taskFactory));
     }
 }
 /// <inheritdoc />
 public Task HandleAsync <T>(IWorkGroup workGroup, IReceivedMessage <T> message, IWorkerNotification notifications, Action <IReceivedMessage <T>, IWorkerNotification> functionToRun, ITaskFactory taskFactory) where T : class
 {
     using (var scope = _tracer.StartActivity("SchedulerMessageHandler"))
     {
         return(_handler.HandleAsync(workGroup, message, notifications, functionToRun, taskFactory));
     }
 }
예제 #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="WorkGroupWithItem"/> class.
        /// </summary>
        /// <param name="sourceGroup">The source group.</param>
        /// <param name="metricCounter">A counter for tracking how many items are being processed</param>
        public WorkGroupWithItem(IWorkGroup sourceGroup, ICounter metricCounter)
        {
            Guard.NotNull(() => sourceGroup, sourceGroup);
            Guard.NotNull(() => metricCounter, metricCounter);

            GroupInfo     = sourceGroup;
            MaxWorkItems  = GroupInfo.ConcurrencyLevel + GroupInfo.MaxQueueSize;
            MetricCounter = metricCounter;
        }
예제 #4
0
        /// <summary>
        /// Tries to add a new work group to the collection
        /// </summary>
        /// <remarks>Will gracefully handle another thread adding the group</remarks>
        /// <param name="group">The group.</param>
        private void TryAdd(IWorkGroup group)
        {
            var newWaitEvent = _waitForEventOrCancelFactory.Create();

            if (!_waitForEventForGroups.TryAdd(group, newWaitEvent))
            {
                //already added by another thread, nuke the one we just created
                newWaitEvent.Dispose();
            }
        }
예제 #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="WorkGroupWithItem"/> class.
        /// </summary>
        /// <param name="sourceGroup">The source group.</param>
        /// <param name="threadGroup">The thread group.</param>
        /// <param name="metricCounter">A counter for tracking how many items are being processed</param>
        public WorkGroupWithItem(IWorkGroup sourceGroup, IWorkItemsGroup threadGroup, ICounter metricCounter)
        {
            Guard.NotNull(() => sourceGroup, sourceGroup);
            Guard.NotNull(() => threadGroup, threadGroup);
            Guard.NotNull(() => metricCounter, metricCounter);

            GroupInfo = sourceGroup;
            Group = threadGroup;
            MaxWorkItems = GroupInfo.ConcurrencyLevel + GroupInfo.MaxQueueSize;
            MetricCounter = metricCounter;
        }
예제 #6
0
        private SchedulerMethod Create(int workerCount, IWorkGroup workGroup = null)
        {
            var fixture             = new Fixture().Customize(new AutoNSubstituteCustomization());
            var cancelWork          = fixture.Create <IQueueCancelWork>();
            var workerConfiguration = fixture.Create <IWorkerConfiguration>();

            workerConfiguration.WorkerCount.Returns(workerCount);

            fixture.Inject(cancelWork);
            fixture.Inject(workerConfiguration);


            cancelWork.CancellationTokenSource.Returns(new CancellationTokenSource());
            cancelWork.StopTokenSource.Returns(new CancellationTokenSource());

            var stopWorker = fixture.Create <StopWorker>();

            fixture.Inject(stopWorker);

            IConsumerQueueAsync queue = fixture.Create <ConsumerQueueAsync>();
            var fixture2 = new Fixture().Customize(new AutoNSubstituteCustomization());

            fixture2.Inject(queue);

            var factoryFactory = fixture2.Create <ITaskFactoryFactory>();

            fixture2.Inject(factoryFactory);

            IConsumerQueueScheduler scheduler = fixture2.Create <Scheduler>();

            fixture2.Inject(scheduler);

            ATaskScheduler schedule = new CreateContainerTest.TaskSchedulerNoOp();

            schedule.Start();
            fixture2.Inject(schedule);
            var taskFactory = fixture2.Create <ITaskFactory>();

            taskFactory.Scheduler.Returns(schedule);
            fixture2.Inject(taskFactory);

            factoryFactory.Create().Returns(taskFactory);

            if (workGroup != null)
            {
                fixture2.Inject(workGroup);
            }

            var handler = fixture2.Create <SchedulerMessageHandler>();

            fixture2.Inject(handler);

            return(fixture2.Create <SchedulerMethod>());
        }
예제 #7
0
        /// <summary>
        /// De-increments the task counter for a specific group.
        /// </summary>
        /// <param name="group">The group.</param>
        protected virtual void DecrementGroup(IWorkGroup group)
        {
            var current = Interlocked.Decrement(ref _groups[group].CurrentWorkItems);

            if (_logger.IsEnabled(LogLevel.Trace))
            {
                _logger.Log(LogLevel.Trace, $"Task count for group {group.Name} is {current}");

                var queue = Interlocked.Read(ref _currentTaskCount);
                _logger.Log(LogLevel.Trace, $"Task count is {queue} with the max being {_configuration.MaximumThreads}");
            }
        }
예제 #8
0
        /// <inheritdoc />
        public override RoomForNewTaskResult RoomForNewWorkGroupTask(IWorkGroup group)
        {
            if (IsDisposed)
            {
                return(RoomForNewTaskResult.No);
            }

            if (HaveRoomForWorkGroupTask(group))
            {
                return(CurrentTaskCount > _groups[group].GroupInfo.ConcurrencyLevel ? RoomForNewTaskResult.RoomInQueue : RoomForNewTaskResult.RoomForTask);
            }
            return(RoomForNewTaskResult.No);
        }
예제 #9
0
        /// <inheritdoc />
        public override RoomForNewTaskResult RoomForNewWorkGroupTask(IWorkGroup group)
        {
            if (IsDisposed)
            {
                return(RoomForNewTaskResult.No);
            }

            if (HaveRoomForWorkGroupTask(group))
            {
                return(RoomForNewTaskResult.RoomForTask);
            }
            return(RoomForNewTaskResult.No);
        }
        /// <summary>
        /// Waits until notified to stop waiting.
        /// </summary>
        /// <param name="group">The group.</param>
        /// <returns></returns>
        public bool Wait(IWorkGroup group)
        {
            ThrowIfDisposed();

            if (group == null)
            {
                return _waitForEvent.Value.Wait();
            }

            if (!_waitForEventForGroups.ContainsKey(group))
            {
                //kind of weird to get to this spot, but lets add a group anyway
                TryAdd(group);
            }
            return _waitForEventForGroups[group].Wait();
        }
예제 #11
0
        /// <summary>
        /// Waits until notified to stop waiting.
        /// </summary>
        /// <param name="group">The group.</param>
        /// <returns></returns>
        public bool Wait(IWorkGroup group)
        {
            ThrowIfDisposed();

            if (group == null)
            {
                return(_waitForEvent.Value.Wait());
            }

            if (!_waitForEventForGroups.ContainsKey(group))
            {
                //kind of weird to get to this spot, but lets add a group anyway
                TryAdd(group);
            }
            return(_waitForEventForGroups[group].Wait());
        }
예제 #12
0
        /// <summary>
        /// Resets the wait status, causing <see cref="Wait" /> calls to wait.
        /// </summary>
        /// <param name="group">The group.</param>
        public void Reset(IWorkGroup group)
        {
            ThrowIfDisposed();

            if (group == null)
            {
                _waitForEvent.Value.Reset();
            }
            else
            {
                if (!_waitForEventForGroups.ContainsKey(group))
                {
                    TryAdd(group);
                }
                _waitForEventForGroups[group].Reset();
            }
        }
        /// <summary>
        /// Resets the wait status, causing <see cref="Wait" /> calls to wait.
        /// </summary>
        /// <param name="group">The group.</param>
        public void Reset(IWorkGroup group)
        {
            ThrowIfDisposed();

            if (group == null)
            {
                _waitForEvent.Value.Reset();
            }
            else
            {
                if (!_waitForEventForGroups.ContainsKey(group))
                {
                    TryAdd(group);
                }
                _waitForEventForGroups[group].Reset();
            }
        }
예제 #14
0
        /// <summary>
        /// Sets the state to signaled; any <see cref="Wait" /> calls will return
        /// </summary>
        /// <param name="group">The group.</param>
        public void Set(IWorkGroup group)
        {
            ThrowIfDisposed();

            if (group == null)
            {
                _waitForEvent.Value.Set();
            }
            else
            {
                Guard.NotNull(() => group, group);
                if (!_waitForEventForGroups.ContainsKey(group))
                {
                    TryAdd(group);
                }
                _waitForEventForGroups[group].Set();
            }
        }
예제 #15
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Scheduler" /> class.
        /// </summary>
        /// <param name="queue">The queue.</param>
        /// <param name="schedulerMessageHandler">The message handler.</param>
        /// <param name="factory">The factory.</param>
        /// <param name="workGroup">The work group.</param>
        public Scheduler(IConsumerQueueAsync queue,
                         ISchedulerMessageHandler schedulerMessageHandler,
                         ITaskFactoryFactory factory,
                         IWorkGroup workGroup)
        {
            Guard.NotNull(() => queue, queue);
            Guard.NotNull(() => schedulerMessageHandler, schedulerMessageHandler);
            Guard.NotNull(() => factory, factory);

            _queue = queue;
            _schedulerMessageHandler = schedulerMessageHandler;
            _taskFactory             = new Lazy <ITaskFactory>(factory.Create);

            //if the work group is not set, we are going to just treat it as null
            if (!string.IsNullOrEmpty(workGroup?.Name))
            {
                WorkGroup = workGroup;
            }
        }
예제 #16
0
 public override RoomForNewTaskResult RoomForNewWorkGroupTask(IWorkGroup group)
 {
     return(RoomForNewTaskResult.No);
 }
예제 #17
0
 public WorkGroup()
 {
     this.dataWorkGroup = RoadFlow.Data.Factory.Factory.GetWorkGroup();
 }
예제 #18
0
 /// <summary>
 /// Initializes a new instance of the <see cref="StateInformation"/> class.
 /// </summary>
 /// <param name="group">The work group; Can be null</param>
 public StateInformation(IWorkGroup group)
 {
     Group = group;
 }
        /// <summary>
        /// Sets the state to signaled; any <see cref="Wait" /> calls will return
        /// </summary>
        /// <param name="group">The group.</param>
        public void Set(IWorkGroup group)
        {
            ThrowIfDisposed();

            if (group == null)
            {
                _waitForEvent.Value.Set();
            }
            else
            {
                Guard.NotNull(() => group, group);
                if (!_waitForEventForGroups.ContainsKey(group))
                {
                    TryAdd(group);
                }
                _waitForEventForGroups[group].Set();
            }
        }
예제 #20
0
 /// <summary>
 /// Returns true if the work group has room for a new task
 /// </summary>
 /// <param name="group">The group.</param>
 /// <returns></returns>
 protected virtual bool HaveRoomForWorkGroupTask(IWorkGroup group)
 {
     return(Interlocked.CompareExchange(ref _groups[group].CurrentWorkItems, 0, 0) < _groups[group].MaxWorkItems);
 }
예제 #21
0
        /// <summary>
        /// Creates an async consumer queue that uses a task scheduler
        /// </summary>
        /// <param name="queue">The queue.</param>
        /// <param name="connection">The connection.</param>
        /// <param name="factory">The task factory.</param>
        /// <param name="workGroup">The work group.</param>
        /// <returns></returns>
        public IConsumerQueueScheduler CreateConsumerQueueScheduler(string queue, string connection, ITaskFactory factory, IWorkGroup workGroup)
        {
            Guard.NotNullOrEmpty(() => queue, queue);
            Guard.NotNullOrEmpty(() => connection, connection);

            return(CreateConsumerQueueSchedulerInternal(queue, connection, factory, workGroup, false));
        }
        /// <summary>
        /// Handles the specified message.
        /// </summary>
        /// <typeparam name="T">the type of the message.</typeparam>
        /// <param name="workGroup">The work group.</param>
        /// <param name="message">The message.</param>
        /// <param name="notifications">The notifications.</param>
        /// <param name="functionToRun">The function to run.</param>
        /// <param name="taskFactory">The task factory.</param>
        /// <returns></returns>
        public Task HandleAsync <T>(IWorkGroup workGroup, IReceivedMessage <T> message, IWorkerNotification notifications, Action <IReceivedMessage <T>, IWorkerNotification> functionToRun, ITaskFactory taskFactory)
            where T : class
        {
            Guard.NotNull(() => message, message);
            Guard.NotNull(() => notifications, notifications);
            Guard.NotNull(() => functionToRun, functionToRun);
            Guard.NotNull(() => taskFactory, taskFactory);

            while (true)
            {
                //verify that we are not canceling or stopping before trying to queue the item
                //however, the transport must support rollbacks
                if (!ShouldHandle(notifications))
                {
                    return(null);
                }

                if (taskFactory.TryStartNew(state => { WrappedFunction(message, notifications, functionToRun); }, new StateInformation(workGroup), task =>
                {
                    if (task.IsFaulted && task.Exception?.InnerException is OperationCanceledException)
                    {
                        //bubble the cancel exception; the queue will rollback the message if possible
                        throw new OperationCanceledException("user canceled", task.Exception.InnerException); //explicitly throw this
                    }

                    if (task.IsFaulted && task.Exception != null)
                    {
                        //need to throw it
                        throw new DotNetWorkQueueException("Message processing exception", task.Exception.InnerException);
                    }
                }, out var start).Success())
                {
                    try
                    {
                        return(start);
                    }
                    finally
                    {
                        //block here if the scheduler is full
                        try
                        {
                            _waitingOnFreeThreadCounter.Increment();
                            taskFactory.Scheduler.WaitForFreeThread.Wait(workGroup);
                        }
                        finally
                        {
                            _waitingOnFreeThreadCounter.Decrement();
                        }
                    }
                }

                //block if the scheduler is full
                try
                {
                    _waitingOnFreeThreadCounter.Increment();
                    taskFactory.Scheduler.WaitForFreeThread.Wait(workGroup);
                }
                finally
                {
                    _waitingOnFreeThreadCounter.Decrement();
                }
            }
        }
예제 #23
0
 /// <summary>
 /// De-increments the task counter for a specific group.
 /// </summary>
 /// <param name="group">The group.</param>
 protected virtual void DecrementGroup(IWorkGroup group)
 {
     Interlocked.Decrement(ref _groups[group].CurrentWorkItems);
 }
예제 #24
0
 /// <summary>
 /// Sets the wait handle.
 /// </summary>
 /// <param name="group">The group.</param>
 protected void SetWaitHandle(IWorkGroup group)
 {
     if (group == null) //not a work group
     {
         if (HaveRoomForTask)
         {
             _waitForFreeThread.Set(null);
         }
         else
         {
             _waitForFreeThread.Reset(null);
         }
     }
     else //work group
     {
         if (HaveRoomForTask && HaveRoomForWorkGroupTask(group))
         {
             _waitForFreeThread.Set(group);
         }
         else
         {
             _waitForFreeThread.Reset(group);
         }
     }
 }
예제 #25
0
        /// <summary>
        /// If true, the task scheduler has room for the specified work group task
        /// </summary>
        /// <param name="group">The group.</param>
        /// <returns></returns>
        public override RoomForNewTaskResult RoomForNewWorkGroupTask(IWorkGroup group)
        {
            if (IsDisposed)
                return RoomForNewTaskResult.No;

            if (HaveRoomForWorkGroupTask(group))
            {
                return CurrentTaskCount > _groups[group].GroupInfo.ConcurrencyLevel ? RoomForNewTaskResult.RoomInQueue : RoomForNewTaskResult.RoomForTask;
            }
            return RoomForNewTaskResult.No;
        }
예제 #26
0
 /// <summary>
 /// De-increments the task counter for a specific group.
 /// </summary>
 /// <param name="group">The group.</param>
 protected virtual void DeincrementGroup(IWorkGroup group)
 {
     Interlocked.Decrement(ref _groups[group].CurrentWorkItems);
 }
예제 #27
0
 /// <summary>
 /// Returns true if the work group has room for a new task
 /// </summary>
 /// <param name="group">The group.</param>
 /// <returns></returns>
 protected virtual bool HaveRoomForWorkGroupTask(IWorkGroup group)
 {
    return Interlocked.CompareExchange(ref _groups[group].CurrentWorkItems, 0, 0) < _groups[group].MaxWorkItems;
 }
예제 #28
0
 /// <summary>
 /// If true, the task scheduler has room for the specified work group task
 /// </summary>
 /// <param name="group">The group.</param>
 /// <returns></returns>
 public abstract RoomForNewTaskResult RoomForNewWorkGroupTask(IWorkGroup group);
예제 #29
0
 /// <summary>
 /// If true, the task scheduler has room for the specified work group task
 /// </summary>
 /// <param name="group">The group.</param>
 /// <returns></returns>
 public abstract RoomForNewTaskResult RoomForNewWorkGroupTask(IWorkGroup group);
예제 #30
0
 /// <summary>
 /// Initializes a new instance of the <see cref="StateInformation"/> class.
 /// </summary>
 /// <param name="group">The work group; Can be null</param>
 public StateInformation(IWorkGroup group)
 {
     Group = group;
 }
예제 #31
0
        /// <summary>
        /// Creates an async consumer queue that uses a task scheduler
        /// </summary>
        /// <param name="queueConnection">Queue and connection information.</param>
        /// <param name="factory">The task factory.</param>
        /// <param name="workGroup">The work group.</param>
        /// <returns></returns>
        public IConsumerQueueScheduler CreateConsumerQueueScheduler(QueueConnection queueConnection, ITaskFactory factory, IWorkGroup workGroup)
        {
            Guard.NotNull(() => queueConnection, queueConnection);

            return(CreateConsumerQueueSchedulerInternal(queueConnection, factory, workGroup, false));
        }
예제 #32
0
 public WorkGroup()
 {
     dataWorkGroup = Factory.GetWorkGroup();
 }
예제 #33
0
        /// <summary>
        /// Creates the consumer method queue scheduler.
        /// </summary>
        /// <param name="queueConnection">Queue and connection information.</param>
        /// <param name="factory">The factory.</param>
        /// <param name="workGroup">The work group.</param>
        /// <param name="internalFactory">if set to <c>true</c> [internal factory].</param>
        /// <returns></returns>
        private IConsumerMethodQueueScheduler CreateConsumerMethodQueueSchedulerInternal(QueueConnection queueConnection, ITaskFactory factory, IWorkGroup workGroup, bool internalFactory)
        {
            Guard.NotNull(() => queueConnection, queueConnection);

            IContainer container;

            if (internalFactory) //we own factory
            {
                if (workGroup == null)
                {
                    container = _createContainerInternal()
                                .Create(QueueContexts.ConsumerMethodQueueScheduler, _registerService, queueConnection,
                                        _transportInit, ConnectionTypes.Receive,
                                        serviceRegister =>
                                        serviceRegister.Register(() => factory, LifeStyles.Singleton)
                                        .Register <IWorkGroup>(() => new WorkGroupNoOp(), LifeStyles.Singleton)
                                        .Register(() => factory.Scheduler, LifeStyles.Singleton), _setOptions);
                }
                else
                {
                    container = _createContainerInternal()
                                .Create(QueueContexts.ConsumerMethodQueueScheduler, _registerService, queueConnection,
                                        _transportInit, ConnectionTypes.Receive,
                                        serviceRegister =>
                                        serviceRegister.Register(() => factory, LifeStyles.Singleton)
                                        .Register(() => workGroup, LifeStyles.Singleton)
                                        .Register(() => factory.Scheduler, LifeStyles.Singleton), _setOptions);
                }
            }
            else  //someone else owns factory
            {
                if (workGroup == null)
                {
                    container = _createContainerInternal()
                                .Create(QueueContexts.ConsumerMethodQueueScheduler, _registerService, queueConnection,
                                        _transportInit, ConnectionTypes.Receive,
                                        serviceRegister =>
                                        serviceRegister.RegisterNonScopedSingleton(factory)
                                        .Register <IWorkGroup>(() => new WorkGroupNoOp(), LifeStyles.Singleton)
                                        .RegisterNonScopedSingleton(factory.Scheduler), _setOptions);
                }
                else
                {
                    container = _createContainerInternal()
                                .Create(QueueContexts.ConsumerMethodQueueScheduler, _registerService, queueConnection,
                                        _transportInit, ConnectionTypes.Receive,
                                        serviceRegister =>
                                        serviceRegister.RegisterNonScopedSingleton(factory)
                                        .Register(() => workGroup, LifeStyles.Singleton)
                                        .RegisterNonScopedSingleton(factory.Scheduler), _setOptions);
                }
            }
            Containers.Add(container);
            return(container.GetInstance <IConsumerMethodQueueScheduler>());
        }
        private SchedulerMethod Create(int workerCount, IWorkGroup workgroup = null)
        {
            var fixture = new Fixture().Customize(new AutoNSubstituteCustomization());
            var cancelWork = fixture.Create<IQueueCancelWork>();
            var workerConfiguration = fixture.Create<IWorkerConfiguration>();
            workerConfiguration.WorkerCount.Returns(workerCount);

            fixture.Inject(cancelWork);
            fixture.Inject(workerConfiguration);


            cancelWork.CancellationTokenSource.Returns(new CancellationTokenSource());
            cancelWork.StopTokenSource.Returns(new CancellationTokenSource());

            var stopWorker = fixture.Create<StopWorker>();
            fixture.Inject(stopWorker);

            IConsumerQueueAsync queue = fixture.Create<ConsumerQueueAsync>();
            var fixture2 = new Fixture().Customize(new AutoNSubstituteCustomization());
            fixture2.Inject(queue);

            ITaskFactoryFactory factoryFactory = fixture2.Create<ITaskFactoryFactory>();
            fixture2.Inject(factoryFactory);

            IConsumerQueueScheduler scheulder = fixture2.Create<Scheduler>();
            fixture2.Inject(scheulder);

            ATaskScheduler schedule = new CreateContainerTest.TaskSchedulerNoOp();
            schedule.Start();
            fixture2.Inject(schedule);
            var taskFactory = fixture2.Create<ITaskFactory>();
            taskFactory.Scheduler.Returns(schedule);
            fixture2.Inject(taskFactory);

            factoryFactory.Create().Returns(taskFactory);

            if (workgroup != null)
                fixture2.Inject(workgroup);

            var handler = fixture2.Create<SchedulerMessageHandler>();
            fixture2.Inject(handler);

            return fixture2.Create<SchedulerMethod>();
        }
 /// <summary>
 /// Tries to add a new work group to the collection
 /// </summary>
 /// <remarks>Will gracefully handle another thread adding the group</remarks>
 /// <param name="group">The group.</param>
 private void TryAdd(IWorkGroup group)
 {
     var newWaitEvent = _waitForEventOrCancelFactory.Create();
     if (!_waitForEventForGroups.TryAdd(group, newWaitEvent))
     {
         //already added by another thread, nuke the one we just created
         newWaitEvent.Dispose();
     }
 }