/// <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)); } }
/// <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; }
/// <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(); } }
/// <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; }
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>()); }
/// <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}"); } }
/// <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); }
/// <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(); }
/// <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()); }
/// <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> /// 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(); } }
/// <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; } }
public override RoomForNewTaskResult RoomForNewWorkGroupTask(IWorkGroup group) { return(RoomForNewTaskResult.No); }
public WorkGroup() { this.dataWorkGroup = RoadFlow.Data.Factory.Factory.GetWorkGroup(); }
/// <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> /// 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); }
/// <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(); } } }
/// <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); }
/// <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); } } }
/// <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; }
/// <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); }
/// <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; }
/// <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);
/// <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)); }
public WorkGroup() { dataWorkGroup = Factory.GetWorkGroup(); }
/// <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>(); }