public async Task CanRunWorkItemJobUntilEmpty() { using (var queue = new InMemoryQueue <WorkItemData>(new InMemoryQueueOptions <WorkItemData> { LoggerFactory = Log })) { using (var messageBus = new InMemoryMessageBus(new InMemoryMessageBusOptions { LoggerFactory = Log })) { var handlerRegistry = new WorkItemHandlers(); var job = new WorkItemJob(queue, messageBus, handlerRegistry, Log); handlerRegistry.Register <MyWorkItem>(new MyWorkItemHandler(Log)); await queue.EnqueueAsync(new MyWorkItem { SomeData = "Test" }, true); await queue.EnqueueAsync(new MyWorkItem { SomeData = "Test" }, true); await job.RunUntilEmptyAsync(); var stats = await queue.GetQueueStatsAsync(); Assert.Equal(2, stats.Enqueued); Assert.Equal(2, stats.Dequeued); Assert.Equal(2, stats.Completed); } } }
public async Task TestAsyncEvents() { var q = new InMemoryQueue<SimpleWorkItem>(); q.Enqueuing.AddHandler(async (sender, args) => { await Task.Delay(250); Logger.Info().Message("First Enqueuing.").Write(); }); q.Enqueuing.AddHandler(async(sender, args) => { await Task.Delay(250); Logger.Info().Message("Second Enqueuing.").Write(); }); var e1 = q.Enqueued.AddHandler(async (sender, args) => { await Task.Delay(250); Logger.Info().Message("First.").Write(); }); q.Enqueued.AddHandler(async(sender, args) => { await Task.Delay(250); Logger.Info().Message("Second.").Write(); }); var sw = Stopwatch.StartNew(); await q.EnqueueAsync(new SimpleWorkItem()); sw.Stop(); _writer.WriteLine(sw.Elapsed.ToString()); e1.Dispose(); sw.Restart(); await q.EnqueueAsync(new SimpleWorkItem()); sw.Stop(); _writer.WriteLine(sw.Elapsed.ToString()); }
public async Task TestAsyncEvents() { var q = new InMemoryQueue <SimpleWorkItem>(loggerFactory: Log); q.Enqueuing.AddHandler(async(sender, args) => { await Task.Delay(250); _logger.Info("First Enqueuing."); }); q.Enqueuing.AddHandler(async(sender, args) => { await Task.Delay(250); _logger.Info("Second Enqueuing."); }); var e1 = q.Enqueued.AddHandler(async(sender, args) => { await Task.Delay(250); _logger.Info("First."); }); q.Enqueued.AddHandler(async(sender, args) => { await Task.Delay(250); _logger.Info("Second."); }); var sw = Stopwatch.StartNew(); await q.EnqueueAsync(new SimpleWorkItem()); sw.Stop(); _logger.Trace(sw.Elapsed.ToString()); e1.Dispose(); sw.Restart(); await q.EnqueueAsync(new SimpleWorkItem()); sw.Stop(); _logger.Trace(sw.Elapsed.ToString()); }
public async Task TestAsyncEvents() { using (var q = new InMemoryQueue <SimpleWorkItem>(new InMemoryQueueOptions <SimpleWorkItem> { LoggerFactory = Log })) { var disposables = new List <IDisposable>(5); try { disposables.Add(q.Enqueuing.AddHandler(async(sender, args) => { await SystemClock.SleepAsync(250); _logger.LogInformation("First Enqueuing."); })); disposables.Add(q.Enqueuing.AddHandler(async(sender, args) => { await SystemClock.SleepAsync(250); _logger.LogInformation("Second Enqueuing."); })); disposables.Add(q.Enqueued.AddHandler(async(sender, args) => { await SystemClock.SleepAsync(250); _logger.LogInformation("First."); })); disposables.Add(q.Enqueued.AddHandler(async(sender, args) => { await SystemClock.SleepAsync(250); _logger.LogInformation("Second."); })); var sw = Stopwatch.StartNew(); await q.EnqueueAsync(new SimpleWorkItem()); sw.Stop(); if (_logger.IsEnabled(LogLevel.Trace)) { _logger.LogTrace("Time {Elapsed:g}", sw.Elapsed); } sw.Restart(); await q.EnqueueAsync(new SimpleWorkItem()); sw.Stop(); if (_logger.IsEnabled(LogLevel.Trace)) { _logger.LogTrace("Time {Elapsed:g}", sw.Elapsed); } } finally { foreach (var disposable in disposables) { disposable.Dispose(); } } } }
public async Task CanRunWorkItemWithClassHandler() { ServiceProvider.SetServiceProvider(typeof(MyBootstrappedServiceProvider)); var queue = new InMemoryQueue <WorkItemData>(); var messageBus = new InMemoryMessageBus(); var handlerRegistry = new WorkItemHandlers(); var job = new WorkItemJob(queue, messageBus, handlerRegistry, Log); handlerRegistry.Register <MyWorkItem, MyWorkItemHandler>(); var jobId = await queue.EnqueueAsync(new MyWorkItem { SomeData = "Test" }, true); int statusCount = 0; messageBus.Subscribe <WorkItemStatus>(status => { _logger.Trace("Progress: {progress}", status.Progress); Assert.Equal(jobId, status.WorkItemId); statusCount++; }); await job.RunUntilEmptyAsync(); Assert.Equal(11, statusCount); }
public async Task CanRunWorkItemWithClassHandler() { using (var queue = new InMemoryQueue <WorkItemData>(new InMemoryQueueOptions <WorkItemData> { LoggerFactory = Log })) { using (var messageBus = new InMemoryMessageBus(new InMemoryMessageBusOptions { LoggerFactory = Log })) { var handlerRegistry = new WorkItemHandlers(); var job = new WorkItemJob(queue, messageBus, handlerRegistry, Log); handlerRegistry.Register <MyWorkItem>(new MyWorkItemHandler(Log)); string jobId = await queue.EnqueueAsync(new MyWorkItem { SomeData = "Test" }, true); int statusCount = 0; await messageBus.SubscribeAsync <WorkItemStatus>(status => { _logger.Trace("Progress: {progress}", status.Progress); Assert.Equal(jobId, status.WorkItemId); statusCount++; }); await job.RunUntilEmptyAsync(); Assert.Equal(11, statusCount); } } }
public async Task CanRunBadWorkItem() { using (var queue = new InMemoryQueue <WorkItemData>(new InMemoryQueueOptions <WorkItemData> { RetryDelay = TimeSpan.FromMilliseconds(500), LoggerFactory = Log })) { using (var messageBus = new InMemoryMessageBus(new InMemoryMessageBusOptions { LoggerFactory = Log })) { var handlerRegistry = new WorkItemHandlers(); var job = new WorkItemJob(queue, messageBus, handlerRegistry, Log); handlerRegistry.Register <MyWorkItem>(ctx => { var jobData = ctx.GetData <MyWorkItem>(); Assert.Equal("Test", jobData.SomeData); throw new Exception(); }); string jobId = await queue.EnqueueAsync(new MyWorkItem { SomeData = "Test" }, true); int statusCount = 0; await messageBus.SubscribeAsync <WorkItemStatus>(status => { _logger.Trace("Progress: {progress}", status.Progress); Assert.Equal(jobId, status.WorkItemId); statusCount++; }); await job.RunUntilEmptyAsync(); Assert.Equal(1, statusCount); } } }
public void WorkItemsWillGetMovedToDeadletter() { var queue = new InMemoryQueue<SimpleWorkItem>(retries: 1, workItemTimeoutMilliseconds: 10); queue.EnqueueAsync(new SimpleWorkItem { Data = "Hello" }); var workItem = queue.DequeueAsync(0).Result; Assert.Equal("Hello", workItem.Value.Data); Assert.Equal(1, queue.Dequeued); Assert.Equal(0, queue.Count); // wait for the task to be auto abandoned Task.Delay(100).Wait(); Assert.Equal(1, queue.Count); Assert.Equal(1, queue.Abandoned); // work item should be retried 1 time. workItem = queue.DequeueAsync(0).Result; Assert.Equal("Hello", workItem.Value.Data); Assert.Equal(2, queue.Dequeued); Task.Delay(100).Wait(); // work item should be moved to deadletter queue after retries. Assert.Equal(1, queue.DeadletterCount); Assert.Equal(2, queue.Abandoned); }
public void CanHaveMultipleWorkers() { const int workItemCount = 50; var latch = new CountDownLatch(workItemCount); int errorCount = 0; int abandonCount = 0; var queue = new InMemoryQueue <SimpleWorkItem>(retries: 1, workItemTimeoutMilliseconds: 50, retryDelayMilliseconds: 0); Parallel.For(0, workItemCount, i => queue.EnqueueAsync(new SimpleWorkItem { Data = "Hello", Id = i })); Task.Factory.StartNew(() => queue.StartWorking(w => DoWork(w, latch, ref abandonCount, ref errorCount))); Task.Factory.StartNew(() => queue.StartWorking(w => DoWork(w, latch, ref abandonCount, ref errorCount))); Task.Factory.StartNew(() => queue.StartWorking(w => DoWork(w, latch, ref abandonCount, ref errorCount))); bool success = latch.Wait(2000); Assert.True(success, "Failed to receive all work items."); Task.Delay(50).Wait(); Assert.Equal(workItemCount, queue.Completed + queue.DeadletterCount); Assert.Equal(errorCount, queue.WorkerErrors); Assert.Equal(abandonCount + errorCount, queue.Abandoned); }
public async Task CanRunBadWorkItem() { var queue = new InMemoryQueue <WorkItemData>(retries: 2, retryDelay: TimeSpan.FromMilliseconds(500)); var messageBus = new InMemoryMessageBus(); var handlerRegistry = new WorkItemHandlers(); var job = new WorkItemJob(queue, messageBus, handlerRegistry); handlerRegistry.Register <MyWorkItem>(ctx => { var jobData = ctx.GetData <MyWorkItem>(); Assert.Equal("Test", jobData.SomeData); throw new ApplicationException(); }); var jobId = await queue.EnqueueAsync(new MyWorkItem { SomeData = "Test" }, true); int statusCount = 0; messageBus.Subscribe <WorkItemStatus>(status => { Logger.Trace().Message($"Progress: {status.Progress}").Write(); Assert.Equal(jobId, status.WorkItemId); statusCount++; }); await job.RunUntilEmptyAsync(); Assert.Equal(1, statusCount); }
public void WorkItemsWillGetMovedToDeadletter() { var queue = new InMemoryQueue <SimpleWorkItem>(retries: 1, workItemTimeoutMilliseconds: 10, retryDelayMilliseconds: 10); queue.EnqueueAsync(new SimpleWorkItem { Data = "Hello" }).Wait(); var workItem = queue.DequeueAsync(0).Result; Assert.Equal("Hello", workItem.Value.Data); Assert.Equal(1, queue.Dequeued); Assert.Equal(0, queue.Count); // wait for the task to be auto abandoned Task.Delay(100).Wait(); Assert.Equal(1, queue.Count); Assert.Equal(1, queue.Abandoned); // work item should be retried 1 time. workItem = queue.DequeueAsync(0).Result; Assert.Equal("Hello", workItem.Value.Data); Assert.Equal(2, queue.Dequeued); Task.Delay(100).Wait(); // work item should be moved to deadletter queue after retries. Assert.Equal(1, queue.DeadletterCount); Assert.Equal(2, queue.Abandoned); }
public async Task CanRunBadWorkItem() { using (var queue = new InMemoryQueue <WorkItemData>(o => o.RetryDelay(TimeSpan.FromMilliseconds(500)).LoggerFactory(Log))) { using (var messageBus = new InMemoryMessageBus(o => o.LoggerFactory(Log))) { var handlerRegistry = new WorkItemHandlers(); var job = new WorkItemJob(queue, messageBus, handlerRegistry, Log); handlerRegistry.Register <MyWorkItem>(ctx => { var jobData = ctx.GetData <MyWorkItem>(); Assert.Equal("Test", jobData.SomeData); throw new Exception(); }); string jobId = await queue.EnqueueAsync(new MyWorkItem { SomeData = "Test" }, true); var countdown = new AsyncCountdownEvent(1); await messageBus.SubscribeAsync <WorkItemStatus>(status => { if (_logger.IsEnabled(LogLevel.Trace)) { _logger.LogTrace("Progress: {Progress}", status.Progress); } Assert.Equal(jobId, status.WorkItemId); countdown.Signal(); }); await job.RunUntilEmptyAsync(); await countdown.WaitAsync(TimeSpan.FromSeconds(2)); Assert.Equal(0, countdown.CurrentCount); } } }
public async Task CanRunWorkItem() { using (var queue = new InMemoryQueue<WorkItemData>()) { using (var messageBus = new InMemoryMessageBus()) { var handlerRegistry = new WorkItemHandlers(); var job = new WorkItemJob(queue, messageBus, handlerRegistry, Log); handlerRegistry.Register<MyWorkItem>(async ctx => { var jobData = ctx.GetData<MyWorkItem>(); Assert.Equal("Test", jobData.SomeData); for (int i = 0; i < 10; i++) { await SystemClock.SleepAsync(100); await ctx.ReportProgressAsync(10 * i); } }); var jobId = await queue.EnqueueAsync(new MyWorkItem { SomeData = "Test" }, true); int statusCount = 0; messageBus.Subscribe<WorkItemStatus>(status => { _logger.Trace("Progress: {progress}", status.Progress); Assert.Equal(jobId, status.WorkItemId); statusCount++; }); await job.RunUntilEmptyAsync(); Assert.Equal(12, statusCount); } } }
public async Task CanRunWorkItem() { using (var queue = new InMemoryQueue <WorkItemData>()) { using (var messageBus = new InMemoryMessageBus()) { var handlerRegistry = new WorkItemHandlers(); var job = new WorkItemJob(queue, messageBus, handlerRegistry, Log); handlerRegistry.Register <MyWorkItem>(async ctx => { var jobData = ctx.GetData <MyWorkItem>(); Assert.Equal("Test", jobData.SomeData); for (int i = 0; i < 10; i++) { await SystemClock.SleepAsync(100); await ctx.ReportProgressAsync(10 * i); } }); var jobId = await queue.EnqueueAsync(new MyWorkItem { SomeData = "Test" }, true); int statusCount = 0; messageBus.Subscribe <WorkItemStatus>(status => { _logger.Trace("Progress: {progress}", status.Progress); Assert.Equal(jobId, status.WorkItemId); statusCount++; }); await job.RunUntilEmptyAsync(); Assert.Equal(12, statusCount); } } }
public virtual async Task CanGetBufferedQueueMetrics() { using (var metrics = GetMetricsClient(true) as IBufferedMetricsClient) { var stats = metrics as IMetricsClientStats; if (stats == null) return; using (var queue = new InMemoryQueue<SimpleWorkItem>(behaviors: new[] { new MetricsQueueBehavior<SimpleWorkItem>(metrics, loggerFactory: Log) }, loggerFactory: Log)) { await queue.EnqueueAsync(new SimpleWorkItem { Id = 1, Data = "1" }); await SystemClock.SleepAsync(50); var entry = await queue.DequeueAsync(TimeSpan.Zero); await SystemClock.SleepAsync(30); await entry.CompleteAsync(); await SystemClock.SleepAsync(500); // give queue metrics time await metrics.FlushAsync(); var queueStats = await stats.GetQueueStatsAsync("simpleworkitem"); Assert.Equal(1, queueStats.Count.Max); Assert.Equal(0, queueStats.Count.Last); Assert.Equal(1, queueStats.Enqueued.Count); Assert.Equal(1, queueStats.Dequeued.Count); Assert.Equal(1, queueStats.Completed.Count); Assert.InRange(queueStats.QueueTime.AverageDuration, 50, 200); Assert.InRange(queueStats.ProcessTime.AverageDuration, 30, 200); } } }
public void WorkItemsWillTimeout() { var queue = new InMemoryQueue<SimpleWorkItem>(workItemTimeoutMilliseconds: 10); queue.EnqueueAsync(new SimpleWorkItem { Data = "Hello" }); var workItem = queue.DequeueAsync(0).Result; Assert.Equal("Hello", workItem.Value.Data); Assert.Equal(0, queue.Count); // wait for the task to be auto abandoned Task.Delay(100).Wait(); Assert.Equal(1, queue.Count); Assert.Equal(1, queue.Abandoned); }
public async Task TestAsyncEvents() { using (var q = new InMemoryQueue<SimpleWorkItem>(loggerFactory: Log)) { var disposables = new List<IDisposable>(5); try { disposables.Add(q.Enqueuing.AddHandler(async (sender, args) => { await SystemClock.SleepAsync(250); _logger.Info("First Enqueuing."); })); disposables.Add(q.Enqueuing.AddHandler(async (sender, args) => { await SystemClock.SleepAsync(250); _logger.Info("Second Enqueuing."); })); disposables.Add(q.Enqueued.AddHandler(async (sender, args) => { await SystemClock.SleepAsync(250); _logger.Info("First."); })); disposables.Add(q.Enqueued.AddHandler(async (sender, args) => { await SystemClock.SleepAsync(250); _logger.Info("Second."); })); var sw = Stopwatch.StartNew(); await q.EnqueueAsync(new SimpleWorkItem()); sw.Stop(); _logger.Trace("Time {0}", sw.Elapsed); sw.Restart(); await q.EnqueueAsync(new SimpleWorkItem()); sw.Stop(); _logger.Trace("Time {0}", sw.Elapsed); } finally { foreach (var disposable in disposables) disposable.Dispose(); } } }
public void CanQueueAndDequeueWorkItem() { var queue = new InMemoryQueue<SimpleWorkItem>(); queue.EnqueueAsync(new SimpleWorkItem { Data = "Hello" }); Assert.Equal(1, queue.Count); var workItem = queue.DequeueAsync(0).Result; Assert.NotNull(workItem); Assert.Equal("Hello", workItem.Value.Data); Assert.Equal(0, queue.Count); Assert.Equal(1, queue.Dequeued); workItem.CompleteAsync().Wait(); Assert.Equal(1, queue.Completed); }
public void WorkItemsWillTimeout() { var queue = new InMemoryQueue <SimpleWorkItem>(workItemTimeoutMilliseconds: 10, retryDelayMilliseconds: 0); queue.EnqueueAsync(new SimpleWorkItem { Data = "Hello" }); var workItem = queue.DequeueAsync(0).Result; Assert.Equal("Hello", workItem.Value.Data); Assert.Equal(0, queue.Count); // wait for the task to be auto abandoned Task.Delay(100).Wait(); Assert.Equal(1, queue.Count); Assert.Equal(1, queue.Abandoned); }
public void CanQueueAndDequeueWorkItem() { var queue = new InMemoryQueue <SimpleWorkItem>(); queue.EnqueueAsync(new SimpleWorkItem { Data = "Hello" }); Assert.Equal(1, queue.Count); var workItem = queue.DequeueAsync(0).Result; Assert.NotNull(workItem); Assert.Equal("Hello", workItem.Value.Data); Assert.Equal(0, queue.Count); Assert.Equal(1, queue.Dequeued); workItem.CompleteAsync().Wait(); Assert.Equal(1, queue.Completed); }
public void CanUseQueueWorker() { var resetEvent = new AutoResetEvent(false); var queue = new InMemoryQueue<SimpleWorkItem>(); queue.StartWorking(w => { Assert.Equal("Hello", w.Value.Data); w.CompleteAsync().Wait(); resetEvent.Set(); }); queue.EnqueueAsync(new SimpleWorkItem { Data = "Hello" }); Assert.Equal(1, queue.Count); bool success = resetEvent.WaitOne(250); Assert.Equal(0, queue.Count); Assert.Equal(1, queue.Completed); Assert.True(success, "Failed to receive message."); Assert.Equal(0, queue.WorkerErrors); }
public async Task CanRunWorkItemWithDelegateHandler() { using (var queue = new InMemoryQueue <WorkItemData>(new InMemoryQueueOptions <WorkItemData> { LoggerFactory = Log })) { using (var messageBus = new InMemoryMessageBus(new InMemoryMessageBusOptions { LoggerFactory = Log })) { var handlerRegistry = new WorkItemHandlers(); var job = new WorkItemJob(queue, messageBus, handlerRegistry, Log); handlerRegistry.Register <MyWorkItem>(async ctx => { var jobData = ctx.GetData <MyWorkItem>(); Assert.Equal("Test", jobData.SomeData); for (int i = 1; i < 10; i++) { await SystemClock.SleepAsync(100); await ctx.ReportProgressAsync(10 * i); } }, Log.CreateLogger("MyWorkItem")); string jobId = await queue.EnqueueAsync(new MyWorkItem { SomeData = "Test" }, true); int statusCount = 0; await messageBus.SubscribeAsync <WorkItemStatus>(status => { if (_logger.IsEnabled(LogLevel.Trace)) { _logger.LogTrace("Progress: {Progress}", status.Progress); } Assert.Equal(jobId, status.WorkItemId); Interlocked.Increment(ref statusCount); }); await job.RunUntilEmptyAsync(); Assert.Equal(11, statusCount); } } }
public virtual async Task CanGetBufferedQueueMetricsAsync() { using (var metrics = GetMetricsClient(true) as IBufferedMetricsClient) { var stats = metrics as IMetricsClientStats; if (stats == null) { return; } using (var behavior = new MetricsQueueBehavior <SimpleWorkItem>(metrics, reportCountsInterval: TimeSpan.FromMilliseconds(25), loggerFactory: Log)) { using (var queue = new InMemoryQueue <SimpleWorkItem>(new InMemoryQueueOptions <SimpleWorkItem> { Behaviors = new [] { behavior }, LoggerFactory = Log })) { await queue.EnqueueAsync(new SimpleWorkItem { Id = 1, Data = "1" }); await SystemClock.SleepAsync(50); var entry = await queue.DequeueAsync(TimeSpan.Zero); await SystemClock.SleepAsync(15); await entry.CompleteAsync(); await SystemClock.SleepAsync(100); // give queue metrics time await metrics.FlushAsync(); var queueStats = await stats.GetQueueStatsAsync("simpleworkitem"); Assert.Equal(1, queueStats.Count.Max); Assert.Equal(0, queueStats.Count.Last); Assert.Equal(1, queueStats.Enqueued.Count); Assert.Equal(1, queueStats.Dequeued.Count); Assert.Equal(1, queueStats.Completed.Count); Assert.InRange(queueStats.QueueTime.AverageDuration, 45, 250); Assert.InRange(queueStats.ProcessTime.AverageDuration, 10, 250); } } } }
public async Task CanRunWorkItemWithDelegateHandler() { using (var queue = new InMemoryQueue <WorkItemData>(o => o.LoggerFactory(Log))) { using (var messageBus = new InMemoryMessageBus(o => o.LoggerFactory(Log))) { var handlerRegistry = new WorkItemHandlers(); var job = new WorkItemJob(queue, messageBus, handlerRegistry, Log); handlerRegistry.Register <MyWorkItem>(async ctx => { var jobData = ctx.GetData <MyWorkItem>(); Assert.Equal("Test", jobData.SomeData); for (int i = 1; i < 10; i++) { await SystemClock.SleepAsync(100); await ctx.ReportProgressAsync(10 * i); } }, Log.CreateLogger("MyWorkItem")); string jobId = await queue.EnqueueAsync(new MyWorkItem { SomeData = "Test" }, true); var countdown = new AsyncCountdownEvent(11); await messageBus.SubscribeAsync <WorkItemStatus>(status => { if (_logger.IsEnabled(LogLevel.Trace)) { _logger.LogTrace("Progress: {Progress}", status.Progress); } Assert.Equal(jobId, status.WorkItemId); countdown.Signal(); }); await job.RunUntilEmptyAsync(); await countdown.WaitAsync(TimeSpan.FromSeconds(2)); Assert.Equal(0, countdown.CurrentCount); } } }
public void CanAutoCompleteWorker() { var resetEvent = new AutoResetEvent(false); var queue = new InMemoryQueue <SimpleWorkItem>(workItemTimeoutMilliseconds: 100); queue.StartWorking(w => { Assert.Equal("Hello", w.Value.Data); resetEvent.Set(); }, true); queue.EnqueueAsync(new SimpleWorkItem { Data = "Hello" }); Assert.Equal(1, queue.Count); bool success = resetEvent.WaitOne(100); Assert.True(success, "Failed to recieve message."); Task.Delay(25).Wait(); Assert.Equal(0, queue.Count); Assert.Equal(1, queue.Completed); Assert.Equal(0, queue.WorkerErrors); }
public void CanUseQueueWorker() { var resetEvent = new AutoResetEvent(false); var queue = new InMemoryQueue <SimpleWorkItem>(); queue.EnqueueAsync(new SimpleWorkItem { Data = "Hello" }); queue.StartWorking(w => { Assert.Equal("Hello", w.Value.Data); w.CompleteAsync().Wait(); resetEvent.Set(); }); bool success = resetEvent.WaitOne(250); Assert.Equal(0, queue.Count); Assert.Equal(1, queue.Completed); Assert.True(success, "Failed to receive message."); Assert.Equal(0, queue.WorkerErrors); }
public virtual async Task CanRunWorkItemWithMetrics() { var eventRaised = new ManualResetEvent(false); var metricsClient = new InMemoryMetricsClient(); var behavior = new MetricsQueueBehavior <WorkItemData>(metricsClient, "metric"); var queue = new InMemoryQueue <WorkItemData>(behaviors: new[] { behavior }); queue.Completed.AddHandler((sender, e) => { eventRaised.Set(); return(TaskHelper.Completed()); }); var work = new SimpleWorkItem { Id = 1, Data = "Testing" }; await queue.EnqueueAsync(work); var item = await queue.DequeueAsync(); await item.CompleteAsync(); metricsClient.DisplayStats(_writer); Assert.True(eventRaised.WaitOne(TimeSpan.FromMinutes(1))); Assert.Equal(6, metricsClient.Counters.Count); Assert.Equal(4, metricsClient.Timings.Count); Assert.Equal(1, metricsClient.Counters["metric.workitemdata.simple.enqueued"]?.RecentValue); Assert.Equal(1, metricsClient.Counters["metric.workitemdata.simple.dequeued"]?.RecentValue); Assert.Equal(1, metricsClient.Counters["metric.workitemdata.simple.completed"]?.RecentValue); Assert.True(0 < metricsClient.Timings["metric.workitemdata.simple.queuetime"]?.Count); Assert.True(0 < metricsClient.Timings["metric.workitemdata.simple.processtime"]?.Count); }
public virtual async Task CanGetBufferedQueueMetrics() { using (var metrics = GetMetricsClient(true) as IBufferedMetricsClient) { var stats = metrics as IMetricsClientStats; if (stats == null) { return; } using (var queue = new InMemoryQueue <SimpleWorkItem>(behaviors: new[] { new MetricsQueueBehavior <SimpleWorkItem>(metrics, loggerFactory: Log) }, loggerFactory: Log)) { await queue.EnqueueAsync(new SimpleWorkItem { Id = 1, Data = "1" }); await SystemClock.SleepAsync(50); var entry = await queue.DequeueAsync(TimeSpan.Zero); await SystemClock.SleepAsync(30); await entry.CompleteAsync(); await SystemClock.SleepAsync(500); // give queue metrics time await metrics.FlushAsync(); var queueStats = await stats.GetQueueStatsAsync("simpleworkitem"); Assert.Equal(1, queueStats.Count.Max); Assert.Equal(0, queueStats.Count.Last); Assert.Equal(1, queueStats.Enqueued.Count); Assert.Equal(1, queueStats.Dequeued.Count); Assert.Equal(1, queueStats.Completed.Count); Assert.InRange(queueStats.QueueTime.AverageDuration, 50, 200); Assert.InRange(queueStats.ProcessTime.AverageDuration, 30, 200); } } }
public virtual async Task CanRunWorkItemWithMetrics() { int completedCount = 0; //Log.MinimumLevel = LogLevel.Trace; //Log.SetLogLevel<ScheduledTimer>(LogLevel.Information); //Log.SetLogLevel<InMemoryCacheClient>(LogLevel.Information); using (var metricsClient = new InMemoryMetricsClient(false, loggerFactory: Log)) { var behavior = new MetricsQueueBehavior<WorkItemData>(metricsClient, "metric", loggerFactory: Log, reportCountsInterval: TimeSpan.Zero); using (var queue = new InMemoryQueue<WorkItemData>(behaviors: new[] { behavior }, loggerFactory: Log)) { 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); Assert.InRange((await metricsClient.GetGaugeStatsAsync("metric.workitemdata.count")).Max, 1, 3); Assert.InRange((await metricsClient.GetGaugeStatsAsync("metric.workitemdata.working")).Max, 0, 1); Assert.Equal(3, await metricsClient.GetCounterCountAsync("metric.workitemdata.simple.enqueued")); Assert.Equal(3, await metricsClient.GetCounterCountAsync("metric.workitemdata.enqueued")); Assert.Equal(3, await metricsClient.GetCounterCountAsync("metric.workitemdata.simple.dequeued")); Assert.Equal(3, await metricsClient.GetCounterCountAsync("metric.workitemdata.dequeued")); Assert.Equal(2, await metricsClient.GetCounterCountAsync("metric.workitemdata.simple.completed")); Assert.Equal(2, await metricsClient.GetCounterCountAsync("metric.workitemdata.completed")); Assert.Equal(1, await metricsClient.GetCounterCountAsync("metric.workitemdata.simple.abandoned")); Assert.Equal(1, await metricsClient.GetCounterCountAsync("metric.workitemdata.abandoned")); var queueTiming = await metricsClient.GetTimerStatsAsync("metric.workitemdata.simple.queuetime"); Assert.Equal(3, queueTiming.Count); queueTiming = await metricsClient.GetTimerStatsAsync("metric.workitemdata.queuetime"); Assert.Equal(3, queueTiming.Count); var processTiming = await metricsClient.GetTimerStatsAsync("metric.workitemdata.simple.processtime"); Assert.Equal(3, processTiming.Count); processTiming = await metricsClient.GetTimerStatsAsync("metric.workitemdata.processtime"); Assert.Equal(3, processTiming.Count); var queueStats = await metricsClient.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 metricsClient.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 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 void CanHaveMultipleWorkers() { const int workItemCount = 50; var latch = new CountDownLatch(workItemCount); int errorCount = 0; int abandonCount = 0; var queue = new InMemoryQueue<SimpleWorkItem>(retries: 1, workItemTimeoutMilliseconds: 50); Task.Factory.StartNew(() => queue.StartWorking(w => DoWork(w, latch, ref abandonCount, ref errorCount))); Task.Factory.StartNew(() => queue.StartWorking(w => DoWork(w, latch, ref abandonCount, ref errorCount))); Task.Factory.StartNew(() => queue.StartWorking(w => DoWork(w, latch, ref abandonCount, ref errorCount))); Parallel.For(0, workItemCount, i => queue.EnqueueAsync(new SimpleWorkItem { Data = "Hello", Id = i })); bool success = latch.Wait(1000); Assert.True(success, "Failed to receive all work items."); Task.Delay(50).Wait(); Assert.Equal(workItemCount, queue.Completed + queue.DeadletterCount); Assert.Equal(errorCount, queue.WorkerErrors); Assert.Equal(abandonCount + errorCount, queue.Abandoned); }
public virtual async Task CanRunWorkItemWithMetrics() { var eventRaised = new ManualResetEvent(false); var metricsClient = new InMemoryMetricsClient(); var behavior = new MetricsQueueBehavior<WorkItemData>(metricsClient, "metric"); var queue = new InMemoryQueue<WorkItemData>(behaviors: new[] { behavior }); queue.Completed.AddHandler((sender, e) => { eventRaised.Set(); return TaskHelper.Completed(); }); var work = new SimpleWorkItem { Id = 1, Data = "Testing" }; await queue.EnqueueAsync(work); var item = await queue.DequeueAsync(); await item.CompleteAsync(); metricsClient.DisplayStats(_writer); Assert.True(eventRaised.WaitOne(TimeSpan.FromMinutes(1))); Assert.Equal(6, metricsClient.Counters.Count); Assert.Equal(4, metricsClient.Timings.Count); Assert.Equal(1, metricsClient.Counters["metric.workitemdata.simple.enqueued"]?.RecentValue); Assert.Equal(1, metricsClient.Counters["metric.workitemdata.simple.dequeued"]?.RecentValue); Assert.Equal(1, metricsClient.Counters["metric.workitemdata.simple.completed"]?.RecentValue); Assert.True(0 < metricsClient.Timings["metric.workitemdata.simple.queuetime"]?.Count); Assert.True(0 < metricsClient.Timings["metric.workitemdata.simple.processtime"]?.Count); }
public async Task CanHandleMultipleWorkItemInstances() { const int workItemCount = 1000; using (var metrics = new InMemoryMetricsClient(loggerFactory: Log)) { using (var queue = new InMemoryQueue<WorkItemData>(retries: 0, retryDelay: TimeSpan.Zero, loggerFactory: Log)) { queue.AttachBehavior(new MetricsQueueBehavior<WorkItemData>(metrics, loggerFactory: Log)); using (var messageBus = new InMemoryMessageBus(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); var 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(); messageBus.Subscribe<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); await SystemClock.SleepAsync(100); } catch (TaskCanceledException) {} _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 virtual async Task CanRunWorkItemWithMetrics() { int completedCount = 0; Log.MinimumLevel = LogLevel.Trace; var metricsClient = new InMemoryMetricsClient(false, loggerFactory: Log); var behavior = new MetricsQueueBehavior <WorkItemData>(metricsClient, "metric", loggerFactory: Log, reportCountsInterval: TimeSpan.Zero); var queue = new InMemoryQueue <WorkItemData>(behaviors: new[] { behavior }, loggerFactory: Log); queue.Completed.AddHandler((sender, e) => { completedCount++; return(TaskHelper.Completed); }); _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 Task.Delay(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); Assert.InRange((await metricsClient.GetGaugeStatsAsync("metric.workitemdata.count")).Max, 2, 3); Assert.InRange((await metricsClient.GetGaugeStatsAsync("metric.workitemdata.working")).Max, 0, 1); Assert.Equal(3, await metricsClient.GetCounterCountAsync("metric.workitemdata.simple.enqueued")); Assert.Equal(3, await metricsClient.GetCounterCountAsync("metric.workitemdata.enqueued")); Assert.Equal(3, await metricsClient.GetCounterCountAsync("metric.workitemdata.simple.dequeued")); Assert.Equal(3, await metricsClient.GetCounterCountAsync("metric.workitemdata.dequeued")); Assert.Equal(2, await metricsClient.GetCounterCountAsync("metric.workitemdata.simple.completed")); Assert.Equal(2, await metricsClient.GetCounterCountAsync("metric.workitemdata.completed")); Assert.Equal(1, await metricsClient.GetCounterCountAsync("metric.workitemdata.simple.abandoned")); Assert.Equal(1, await metricsClient.GetCounterCountAsync("metric.workitemdata.abandoned")); var queueTiming = await metricsClient.GetTimerStatsAsync("metric.workitemdata.simple.queuetime"); Assert.Equal(3, queueTiming.Count); queueTiming = await metricsClient.GetTimerStatsAsync("metric.workitemdata.queuetime"); Assert.Equal(3, queueTiming.Count); var processTiming = await metricsClient.GetTimerStatsAsync("metric.workitemdata.simple.processtime"); Assert.Equal(3, processTiming.Count); processTiming = await metricsClient.GetTimerStatsAsync("metric.workitemdata.processtime"); Assert.Equal(3, processTiming.Count); var queueStats = await metricsClient.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.Equal(3, queueStats.Count.Max); Assert.InRange(queueStats.Working.Max, 0, 1); var subQueueStats = await metricsClient.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 CanRunBadWorkItem() { using (var queue = new InMemoryQueue<WorkItemData>(retries: 2, retryDelay: TimeSpan.FromMilliseconds(500))) { using (var messageBus = new InMemoryMessageBus()) { var handlerRegistry = new WorkItemHandlers(); var job = new WorkItemJob(queue, messageBus, handlerRegistry, Log); handlerRegistry.Register<MyWorkItem>(ctx => { var jobData = ctx.GetData<MyWorkItem>(); Assert.Equal("Test", jobData.SomeData); throw new Exception(); }); var jobId = await queue.EnqueueAsync(new MyWorkItem { SomeData = "Test" }, true); int statusCount = 0; messageBus.Subscribe<WorkItemStatus>(status => { _logger.Trace("Progress: {progress}", status.Progress); Assert.Equal(jobId, status.WorkItemId); statusCount++; }); await job.RunUntilEmptyAsync(); Assert.Equal(1, statusCount); } } }
public async Task CanRunWorkItemWithClassHandler() { using (var queue = new InMemoryQueue<WorkItemData>()) { using (var messageBus = new InMemoryMessageBus()) { var handlerRegistry = new WorkItemHandlers(); var job = new WorkItemJob(queue, messageBus, handlerRegistry, Log); handlerRegistry.Register<MyWorkItem>(new MyWorkItemHandler(Log)); var jobId = await queue.EnqueueAsync(new MyWorkItem { SomeData = "Test" }, true); int statusCount = 0; messageBus.Subscribe<WorkItemStatus>(status => { _logger.Trace("Progress: {progress}", status.Progress); Assert.Equal(jobId, status.WorkItemId); statusCount++; }); await job.RunUntilEmptyAsync(); Assert.Equal(11, statusCount); } } }
public virtual async Task CanRunWorkItemWithMetrics() { int completedCount = 0; //Log.MinimumLevel = LogLevel.Trace; //Log.SetLogLevel<ScheduledTimer>(LogLevel.Information); //Log.SetLogLevel<InMemoryCacheClient>(LogLevel.Information); using (var metricsClient = new InMemoryMetricsClient(false, loggerFactory: Log)) { var behavior = new MetricsQueueBehavior <WorkItemData>(metricsClient, "metric", loggerFactory: Log, reportCountsInterval: TimeSpan.Zero); using (var queue = new InMemoryQueue <WorkItemData>(behaviors: new[] { behavior }, loggerFactory: Log)) { 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); Assert.InRange((await metricsClient.GetGaugeStatsAsync("metric.workitemdata.count")).Max, 1, 3); Assert.InRange((await metricsClient.GetGaugeStatsAsync("metric.workitemdata.working")).Max, 0, 1); Assert.Equal(3, await metricsClient.GetCounterCountAsync("metric.workitemdata.simple.enqueued")); Assert.Equal(3, await metricsClient.GetCounterCountAsync("metric.workitemdata.enqueued")); Assert.Equal(3, await metricsClient.GetCounterCountAsync("metric.workitemdata.simple.dequeued")); Assert.Equal(3, await metricsClient.GetCounterCountAsync("metric.workitemdata.dequeued")); Assert.Equal(2, await metricsClient.GetCounterCountAsync("metric.workitemdata.simple.completed")); Assert.Equal(2, await metricsClient.GetCounterCountAsync("metric.workitemdata.completed")); Assert.Equal(1, await metricsClient.GetCounterCountAsync("metric.workitemdata.simple.abandoned")); Assert.Equal(1, await metricsClient.GetCounterCountAsync("metric.workitemdata.abandoned")); var queueTiming = await metricsClient.GetTimerStatsAsync("metric.workitemdata.simple.queuetime"); Assert.Equal(3, queueTiming.Count); queueTiming = await metricsClient.GetTimerStatsAsync("metric.workitemdata.queuetime"); Assert.Equal(3, queueTiming.Count); var processTiming = await metricsClient.GetTimerStatsAsync("metric.workitemdata.simple.processtime"); Assert.Equal(3, processTiming.Count); processTiming = await metricsClient.GetTimerStatsAsync("metric.workitemdata.processtime"); Assert.Equal(3, processTiming.Count); var queueStats = await metricsClient.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 metricsClient.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; var metrics = new InMemoryMetricsClient(); var queue = new InMemoryQueue <WorkItemData>(retries: 0, retryDelay: TimeSpan.Zero); queue.AttachBehavior(new MetricsQueueBehavior <WorkItemData>(metrics)); var messageBus = new InMemoryMessageBus(); var handlerRegistry = new WorkItemHandlers(); var j1 = new WorkItemJob(queue, messageBus, handlerRegistry); var j2 = new WorkItemJob(queue, messageBus, handlerRegistry); var j3 = new WorkItemJob(queue, messageBus, handlerRegistry); int errors = 0; var jobIds = new ConcurrentDictionary <string, int>(); handlerRegistry.Register <MyWorkItem>(async ctx => { var jobData = ctx.GetData <MyWorkItem>(); Assert.Equal("Test", jobData.SomeData); var jobWorkTotal = jobIds.AddOrUpdate(ctx.JobId, 1, (key, value) => value + 1); Logger.Trace().Message($"Job {ctx.JobId} processing work item #: {jobWorkTotal}").Write(); for (int i = 0; i < 10; i++) { await ctx.ReportProgressAsync(10 * i); } if (RandomData.GetBool(1)) { Interlocked.Increment(ref errors); throw new ApplicationException("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(); messageBus.Subscribe <WorkItemStatus>(status => { Logger.Trace().Message($"Progress: {status.Progress}").Write(); 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); await Task.Delay(100); } catch (TaskCanceledException) {} Logger.Info().Message($"Completed: {completedItems.Count} Errors: {errors}").Write(); metrics.DisplayStats(_writer); Assert.Equal(workItemCount, completedItems.Count + errors); Assert.Equal(3, jobIds.Count); Assert.Equal(workItemCount, jobIds.Sum(kvp => kvp.Value)); }
public void CanAutoCompleteWorker() { var resetEvent = new AutoResetEvent(false); var queue = new InMemoryQueue<SimpleWorkItem>(workItemTimeoutMilliseconds: 100); queue.StartWorking(w => { Assert.Equal("Hello", w.Value.Data); resetEvent.Set(); }, true); queue.EnqueueAsync(new SimpleWorkItem { Data = "Hello" }); Assert.Equal(1, queue.Count); bool success = resetEvent.WaitOne(100); Assert.True(success, "Failed to receive message."); Task.Delay(25).Wait(); Assert.Equal(0, queue.Count); Assert.Equal(1, queue.Completed); Assert.Equal(0, queue.WorkerErrors); }
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 async Task CanRunWorkItemWithClassHandler() { ServiceProvider.SetServiceProvider(typeof(MyBootstrappedServiceProvider)); var queue = new InMemoryQueue<WorkItemData>(); var messageBus = new InMemoryMessageBus(); var handlerRegistry = new WorkItemHandlers(); var job = new WorkItemJob(queue, messageBus, handlerRegistry); handlerRegistry.Register<MyWorkItem, MyWorkItemHandler>(); var jobId = await queue.EnqueueAsync(new MyWorkItem { SomeData = "Test" }, true); int statusCount = 0; messageBus.Subscribe<WorkItemStatus>(status => { Logger.Trace().Message($"Progress: {status.Progress}").Write(); Assert.Equal(jobId, status.WorkItemId); statusCount++; }); await job.RunUntilEmptyAsync(); Assert.Equal(11, statusCount); }