diff --git a/src/Foundatio.TestHarness/Queue/QueueTestBase.cs b/src/Foundatio.TestHarness/Queue/QueueTestBase.cs index 2604cdcfe..21fd8bfd4 100644 --- a/src/Foundatio.TestHarness/Queue/QueueTestBase.cs +++ b/src/Foundatio.TestHarness/Queue/QueueTestBase.cs @@ -1063,7 +1063,7 @@ public virtual async Task CanRunWorkItemWithMetricsAsync() { int completedCount = 0; - using var queue = new InMemoryQueue(o => o.LoggerFactory(Log)); + using var queue = new InMemoryQueue(o => o.LoggerFactory(Log).MetricsInterval(TimeSpan.Zero)); Task Handler(object sender, CompletedEventArgs e) { diff --git a/src/Foundatio/Queues/QueueBase.cs b/src/Foundatio/Queues/QueueBase.cs index 0beb3c219..b488ad11a 100644 --- a/src/Foundatio/Queues/QueueBase.cs +++ b/src/Foundatio/Queues/QueueBase.cs @@ -36,6 +36,8 @@ public abstract class QueueBase : MaintenanceBase, IQueue, IHave private readonly List> _behaviors = new(); protected readonly CancellationTokenSource _queueDisposedCancellationTokenSource; private bool _isDisposed; + private QueueStats _queueStats; + private DateTime _nextQueueStatsUpdate = DateTime.MinValue; protected QueueBase(TOptions options) : base(options?.TimeProvider, options?.LoggerFactory) { @@ -62,11 +64,15 @@ protected QueueBase(TOptions options) : base(options?.TimeProvider, options?.Log var queueMetricValues = new InstrumentsValues(() => { + if (options.MetricsInterval > TimeSpan.Zero && _nextQueueStatsUpdate >= _timeProvider.GetUtcNow()) + return (_queueStats.Queued, _queueStats.Working, _queueStats.Deadletter); + + _nextQueueStatsUpdate = _timeProvider.GetUtcNow().UtcDateTime.Add(_options.MetricsInterval); try { using var _ = FoundatioDiagnostics.ActivitySource.StartActivity("Queue Stats: " + _options.Name); - var stats = GetMetricsQueueStats(); - return (stats.Queued, stats.Working, stats.Deadletter); + _queueStats = GetMetricsQueueStats(); + return (_queueStats.Queued, _queueStats.Working, _queueStats.Deadletter); } catch { @@ -138,9 +144,10 @@ public async Task> GetDeadletterItemsAsync(CancellationToken canc protected abstract Task GetQueueStatsImplAsync(); - public Task GetQueueStatsAsync() + public async Task GetQueueStatsAsync() { - return GetQueueStatsImplAsync(); + _queueStats = await GetQueueStatsImplAsync(); + return _queueStats; } protected virtual QueueStats GetMetricsQueueStats() diff --git a/src/Foundatio/Queues/SharedQueueOptions.cs b/src/Foundatio/Queues/SharedQueueOptions.cs index cf1caa5be..b9df709f3 100644 --- a/src/Foundatio/Queues/SharedQueueOptions.cs +++ b/src/Foundatio/Queues/SharedQueueOptions.cs @@ -14,6 +14,11 @@ public class SharedQueueOptions : SharedOptions where T : class /// Allows you to set a prefix on queue metrics. This allows you to have unique metrics for keyed queues (e.g., priority queues). /// public string MetricsPrefix { get; set; } + + /// + /// How often to update queue metrics. Defaults to 30 seconds. + /// + public TimeSpan MetricsInterval { get; set; } = TimeSpan.FromSeconds(30); } public class SharedQueueOptionsBuilder : SharedOptionsBuilder @@ -77,4 +82,16 @@ public TBuilder MetricsPrefix(string prefix) Target.MetricsPrefix = prefix.Trim(); return (TBuilder)this; } + + /// + /// How often to update queue metrics. Defaults to 30 seconds. + /// + public TBuilder MetricsInterval(TimeSpan interval) + { + if (interval < TimeSpan.Zero) + throw new ArgumentOutOfRangeException(nameof(interval)); + + Target.MetricsInterval = interval; + return (TBuilder)this; + } } diff --git a/tests/Foundatio.Tests/Queue/InMemoryQueueTests.cs b/tests/Foundatio.Tests/Queue/InMemoryQueueTests.cs index 8371b7f04..e4fbd373d 100644 --- a/tests/Foundatio.Tests/Queue/InMemoryQueueTests.cs +++ b/tests/Foundatio.Tests/Queue/InMemoryQueueTests.cs @@ -25,6 +25,7 @@ protected override IQueue GetQueue(int retries = 1, TimeSpan? wo .RetryMultipliers(retryMultipliers ?? new[] { 1, 3, 5, 10 }) .WorkItemTimeout(workItemTimeout.GetValueOrDefault(TimeSpan.FromMinutes(5))) .TimeProvider(timeProvider) + .MetricsInterval(TimeSpan.Zero) .LoggerFactory(Log)); if (_logger.IsEnabled(LogLevel.Debug)) _logger.LogDebug("Queue Id: {QueueId}", _queue.QueueId);