public virtual async Task CanRunWorkItemWithMetricsAsync() { int completedCount = 0; using (var metrics = new InMemoryMetricsClient(new InMemoryMetricsClientOptions { Buffered = false, LoggerFactory = Log })) { var behavior = new MetricsQueueBehavior <WorkItemData>(metrics, "metric", TimeSpan.FromMilliseconds(100), loggerFactory: Log); var options = new InMemoryQueueOptions <WorkItemData> { Behaviors = new[] { behavior }, LoggerFactory = Log }; using (var queue = new InMemoryQueue <WorkItemData>(options)) { Func <object, CompletedEventArgs <WorkItemData>, Task> handler = (sender, e) => { completedCount++; return(Task.CompletedTask); }; using (queue.Completed.AddHandler(handler)) { _logger.Trace("Before enqueue"); await queue.EnqueueAsync(new SimpleWorkItem { Id = 1, Data = "Testing" }); await queue.EnqueueAsync(new SimpleWorkItem { Id = 2, Data = "Testing" }); await queue.EnqueueAsync(new SimpleWorkItem { Id = 3, Data = "Testing" }); await SystemClock.SleepAsync(100); _logger.Trace("Before dequeue"); var item = await queue.DequeueAsync(); await item.CompleteAsync(); item = await queue.DequeueAsync(); await item.CompleteAsync(); item = await queue.DequeueAsync(); await item.AbandonAsync(); _logger.Trace("Before asserts"); Assert.Equal(2, completedCount); await SystemClock.SleepAsync(100); // flush metrics queue behaviors await metrics.FlushAsync(); Assert.InRange((await metrics.GetGaugeStatsAsync("metric.workitemdata.count")).Max, 1, 3); Assert.InRange((await metrics.GetGaugeStatsAsync("metric.workitemdata.working")).Max, 0, 1); Assert.Equal(3, await metrics.GetCounterCountAsync("metric.workitemdata.simple.enqueued")); Assert.Equal(3, await metrics.GetCounterCountAsync("metric.workitemdata.enqueued")); Assert.Equal(3, await metrics.GetCounterCountAsync("metric.workitemdata.simple.dequeued")); Assert.Equal(3, await metrics.GetCounterCountAsync("metric.workitemdata.dequeued")); Assert.Equal(2, await metrics.GetCounterCountAsync("metric.workitemdata.simple.completed")); Assert.Equal(2, await metrics.GetCounterCountAsync("metric.workitemdata.completed")); Assert.Equal(1, await metrics.GetCounterCountAsync("metric.workitemdata.simple.abandoned")); Assert.Equal(1, await metrics.GetCounterCountAsync("metric.workitemdata.abandoned")); var queueTiming = await metrics.GetTimerStatsAsync("metric.workitemdata.simple.queuetime"); Assert.Equal(3, queueTiming.Count); queueTiming = await metrics.GetTimerStatsAsync("metric.workitemdata.queuetime"); Assert.Equal(3, queueTiming.Count); var processTiming = await metrics.GetTimerStatsAsync("metric.workitemdata.simple.processtime"); Assert.Equal(3, processTiming.Count); processTiming = await metrics.GetTimerStatsAsync("metric.workitemdata.processtime"); Assert.Equal(3, processTiming.Count); var queueStats = await metrics.GetQueueStatsAsync("metric.workitemdata"); Assert.Equal(3, queueStats.Enqueued.Count); Assert.Equal(3, queueStats.Dequeued.Count); Assert.Equal(2, queueStats.Completed.Count); Assert.Equal(1, queueStats.Abandoned.Count); Assert.InRange(queueStats.Count.Max, 1, 3); Assert.InRange(queueStats.Working.Max, 0, 1); var subQueueStats = await metrics.GetQueueStatsAsync("metric.workitemdata", "simple"); Assert.Equal(3, subQueueStats.Enqueued.Count); Assert.Equal(3, subQueueStats.Dequeued.Count); Assert.Equal(2, subQueueStats.Completed.Count); Assert.Equal(1, subQueueStats.Abandoned.Count); } } } }
public async Task CanHandleMultipleWorkItemInstances() { const int workItemCount = 1000; using (var metrics = new InMemoryMetricsClient(new InMemoryMetricsClientOptions { LoggerFactory = Log })) { var options = new InMemoryQueueOptions <WorkItemData> { Retries = 0, RetryDelay = TimeSpan.Zero, LoggerFactory = Log }; using (var queue = new InMemoryQueue <WorkItemData>(options)) { queue.AttachBehavior(new MetricsQueueBehavior <WorkItemData>(metrics, loggerFactory: Log)); using (var messageBus = new InMemoryMessageBus(new InMemoryMessageBusOptions { LoggerFactory = Log })) { var handlerRegistry = new WorkItemHandlers(); var j1 = new WorkItemJob(queue, messageBus, handlerRegistry, Log); var j2 = new WorkItemJob(queue, messageBus, handlerRegistry, Log); var j3 = new WorkItemJob(queue, messageBus, handlerRegistry, Log); int errors = 0; var jobIds = new ConcurrentDictionary <string, int>(); handlerRegistry.Register <MyWorkItem>(async ctx => { var jobData = ctx.GetData <MyWorkItem>(); Assert.Equal("Test", jobData.SomeData); int jobWorkTotal = jobIds.AddOrUpdate(ctx.JobId, 1, (key, value) => value + 1); if (jobData.Index % 100 == 0) { _logger.Trace("Job {jobId} processing work item #: {jobWorkTotal}", ctx.JobId, jobWorkTotal); } for (int i = 0; i < 10; i++) { await ctx.ReportProgressAsync(10 * i); } if (RandomData.GetBool(1)) { Interlocked.Increment(ref errors); throw new Exception("Boom!"); } }); for (int i = 0; i < workItemCount; i++) { await queue.EnqueueAsync(new MyWorkItem { SomeData = "Test", Index = i }, true); } var completedItems = new List <string>(); object completedItemsLock = new object(); await messageBus.SubscribeAsync <WorkItemStatus>(status => { if (status.Progress == 100) { _logger.Trace("Progress: {progress}", status.Progress); } if (status.Progress < 100) { return; } lock (completedItemsLock) completedItems.Add(status.WorkItemId); }); var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var tasks = new List <Task> { Task.Run(async() => { await j1.RunUntilEmptyAsync(cancellationTokenSource.Token); cancellationTokenSource.Cancel(); }, cancellationTokenSource.Token), Task.Run(async() => { await j2.RunUntilEmptyAsync(cancellationTokenSource.Token); cancellationTokenSource.Cancel(); }, cancellationTokenSource.Token), Task.Run(async() => { await j3.RunUntilEmptyAsync(cancellationTokenSource.Token); cancellationTokenSource.Cancel(); }, cancellationTokenSource.Token) }; try { await Task.WhenAll(tasks); } catch (OperationCanceledException ex) { _logger.Error(ex, $"One or more tasks were cancelled: {ex.Message}"); } await SystemClock.SleepAsync(100); _logger.Info("Completed: {completedItems} Errors: {errors}", completedItems.Count, errors); Assert.Equal(workItemCount, completedItems.Count + errors); Assert.Equal(3, jobIds.Count); Assert.Equal(workItemCount, jobIds.Sum(kvp => kvp.Value)); } } } }
public InMemoryEventQueuer(IQueueStorageInMemory storedQueue, InMemoryQueueOptions queueOptions) { this.storedQueue = storedQueue; this.queueOptions = queueOptions; }