Eliminate Valkey queue polling fallback (phase 2 CPU optimization)

Replace hardcoded 1-5s polling constants with configurable
QueueWaitTimeoutSeconds (default 0 = pure event-driven). Consumers
now only wake on pub/sub notifications, eliminating ~118 idle
XREADGROUP polls per second across 59 services. Override with
VALKEY_QUEUE_WAIT_TIMEOUT env var if a safety-net poll is needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
master
2026-03-10 02:36:01 +02:00
parent 166745f9f9
commit 31cb31d0fb
6 changed files with 68 additions and 41 deletions

View File

@@ -7,24 +7,24 @@ namespace StellaOps.Gateway.WebService.Tests.Transport;
public sealed class QueueWaitExtensionsTests
{
[Fact]
public async Task WaitForMessagesAsync_UsesHeartbeatDerivedTimeout_ForNotifiableQueues()
public async Task WaitForMessagesAsync_DelegatesToNotifiableQueue()
{
var queue = new RecordingNotifiableQueue();
await queue.WaitForMessagesAsync(TimeSpan.FromSeconds(10), CancellationToken.None);
queue.LastTimeout.Should().Be(QueueWaitExtensions.ResolveNotifiableTimeout(TimeSpan.FromSeconds(10)));
// The heartbeat interval is passed as the timeout hint to the notifiable queue.
queue.LastTimeout.Should().Be(TimeSpan.FromSeconds(10));
}
[Theory]
[InlineData(10, 3)]
[InlineData(45, 5)]
[InlineData(1, 1)]
public void ResolveNotifiableTimeout_ClampsToExpectedBounds(int heartbeatSeconds, int expectedSeconds)
[Fact]
public async Task WaitForMessagesAsync_ZeroHeartbeat_PassesZeroToNotifiableQueue()
{
var timeout = QueueWaitExtensions.ResolveNotifiableTimeout(TimeSpan.FromSeconds(heartbeatSeconds));
var queue = new RecordingNotifiableQueue();
timeout.Should().Be(TimeSpan.FromSeconds(expectedSeconds));
await queue.WaitForMessagesAsync(CancellationToken.None);
queue.LastTimeout.Should().Be(TimeSpan.Zero);
}
private sealed class RecordingNotifiableQueue : IMessageQueue<TestMessage>, INotifiableQueue