diff --git a/src/Router/__Libraries/StellaOps.Messaging.Transport.Valkey/ValkeyConnectionFactory.cs b/src/Router/__Libraries/StellaOps.Messaging.Transport.Valkey/ValkeyConnectionFactory.cs
index 98434bfb8..475d0989f 100644
--- a/src/Router/__Libraries/StellaOps.Messaging.Transport.Valkey/ValkeyConnectionFactory.cs
+++ b/src/Router/__Libraries/StellaOps.Messaging.Transport.Valkey/ValkeyConnectionFactory.cs
@@ -81,6 +81,15 @@ public sealed class ValkeyConnectionFactory : IAsyncDisposable
return _connection;
}
+ ///
+ /// Gets a subscriber for Pub/Sub operations.
+ ///
+ public async ValueTask GetSubscriberAsync(CancellationToken cancellationToken = default)
+ {
+ var connection = await GetConnectionAsync(cancellationToken).ConfigureAwait(false);
+ return connection.GetSubscriber();
+ }
+
///
/// Tests the connection by sending a PING command.
///
diff --git a/src/Router/__Libraries/StellaOps.Messaging.Transport.Valkey/ValkeyEventStream.cs b/src/Router/__Libraries/StellaOps.Messaging.Transport.Valkey/ValkeyEventStream.cs
index 3d0f3c9bc..1511b6ba2 100644
--- a/src/Router/__Libraries/StellaOps.Messaging.Transport.Valkey/ValkeyEventStream.cs
+++ b/src/Router/__Libraries/StellaOps.Messaging.Transport.Valkey/ValkeyEventStream.cs
@@ -24,6 +24,8 @@ public sealed class ValkeyEventStream : IEventStream
private const string TenantIdField = "tenantId";
private const string CorrelationIdField = "correlationId";
+ private string NotificationChannel => $"notify:s:{RedisKey}";
+
public ValkeyEventStream(
ValkeyConnectionFactory connectionFactory,
EventStreamOptions options,
@@ -90,6 +92,19 @@ public sealed class ValkeyEventStream : IEventStream
maxLength: _options.MaxLength.HasValue ? (int)_options.MaxLength.Value : null,
useApproximateMaxLength: _options.ApproximateTrimming).ConfigureAwait(false);
+ // Notify subscribers that new data is available (fire-and-forget).
+ try
+ {
+ await db.PublishAsync(
+ RedisChannel.Literal(NotificationChannel),
+ "1",
+ CommandFlags.FireAndForget).ConfigureAwait(false);
+ }
+ catch
+ {
+ // Best-effort notification; subscribers will still poll on timeout fallback.
+ }
+
return EventPublishResult.Succeeded(entryId!);
}
@@ -131,30 +146,47 @@ public sealed class ValkeyEventStream : IEventStream
lastId = info.LastEntryId ?? "0-0";
}
- while (!cancellationToken.IsCancellationRequested)
+ // Subscribe to Pub/Sub notification channel for efficient wakeup.
+ using var notificationSignal = new SemaphoreSlim(0, 1);
+ var subscriber = await _connectionFactory.GetSubscriberAsync(cancellationToken).ConfigureAwait(false);
+ var channel = await subscriber.SubscribeAsync(RedisChannel.Literal(NotificationChannel)).ConfigureAwait(false);
+ channel.OnMessage(_ =>
{
- var entries = await db.StreamReadAsync(
- RedisKey,
- lastId,
- count: 100).ConfigureAwait(false);
+ try { notificationSignal.Release(); }
+ catch (SemaphoreFullException) { /* already signaled */ }
+ });
- if (entries.Length > 0)
+ try
+ {
+ while (!cancellationToken.IsCancellationRequested)
{
- foreach (var entry in entries)
+ var entries = await db.StreamReadAsync(
+ RedisKey,
+ lastId,
+ count: 100).ConfigureAwait(false);
+
+ if (entries.Length > 0)
{
- var streamEvent = ParseEntry(entry);
- if (streamEvent is not null)
+ foreach (var entry in entries)
{
- yield return streamEvent;
+ var streamEvent = ParseEntry(entry);
+ if (streamEvent is not null)
+ {
+ yield return streamEvent;
+ }
+ lastId = entry.Id!;
}
- lastId = entry.Id!;
+ }
+ else
+ {
+ // Wait for Pub/Sub notification or fallback timeout.
+ await notificationSignal.WaitAsync(_options.PollInterval, cancellationToken).ConfigureAwait(false);
}
}
- else
- {
- // No new entries, wait before polling again
- await Task.Delay(_options.PollInterval, cancellationToken).ConfigureAwait(false);
- }
+ }
+ finally
+ {
+ channel.Unsubscribe();
}
}
diff --git a/src/Router/__Libraries/StellaOps.Messaging.Transport.Valkey/ValkeyMessageQueue.cs b/src/Router/__Libraries/StellaOps.Messaging.Transport.Valkey/ValkeyMessageQueue.cs
index 3cd8397c3..e453b9484 100644
--- a/src/Router/__Libraries/StellaOps.Messaging.Transport.Valkey/ValkeyMessageQueue.cs
+++ b/src/Router/__Libraries/StellaOps.Messaging.Transport.Valkey/ValkeyMessageQueue.cs
@@ -14,7 +14,7 @@ namespace StellaOps.Messaging.Transport.Valkey;
/// Valkey/Redis Streams implementation of .
///
/// The message type.
-public sealed class ValkeyMessageQueue : IMessageQueue, IAsyncDisposable
+public sealed class ValkeyMessageQueue : IMessageQueue, INotifiableQueue, IAsyncDisposable
where TMessage : class
{
private const string ProviderNameValue = "valkey";
@@ -36,11 +36,22 @@ public sealed class ValkeyMessageQueue : IMessageQueue, IAsy
private readonly ILogger>? _logger;
private readonly TimeProvider _timeProvider;
private readonly SemaphoreSlim _groupInitLock = new(1, 1);
+ private readonly SemaphoreSlim _subscriptionInitLock = new(1, 1);
private readonly JsonSerializerOptions _jsonOptions;
+ ///
+ /// Semaphore used for notification-based wakeup. Starts at 0 permits.
+ /// Released (up to 1) when a Pub/Sub notification arrives on the queue channel.
+ ///
+ private readonly SemaphoreSlim _notificationSignal = new(0, 1);
+
+ private ChannelMessageQueue? _subscription;
+ private volatile bool _subscribed;
private volatile bool _groupInitialized;
private bool _disposed;
+ private string NotificationChannel => $"notify:q:{_queueOptions.QueueName}";
+
public ValkeyMessageQueue(
ValkeyConnectionFactory connectionFactory,
MessageQueueOptions queueOptions,
@@ -398,6 +409,48 @@ public sealed class ValkeyMessageQueue : IMessageQueue, IAsy
}
}
+ ///
+ public async Task WaitForNotificationAsync(TimeSpan timeout, CancellationToken cancellationToken)
+ {
+ await EnsureNotificationSubscriptionAsync(cancellationToken).ConfigureAwait(false);
+
+ // Wait for a pub/sub signal or timeout (fallback for missed notifications).
+ try
+ {
+ await _notificationSignal.WaitAsync(timeout, cancellationToken).ConfigureAwait(false);
+ }
+ catch (OperationCanceledException)
+ {
+ throw;
+ }
+ }
+
+ private async Task EnsureNotificationSubscriptionAsync(CancellationToken cancellationToken)
+ {
+ if (_subscribed) return;
+
+ await _subscriptionInitLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+ try
+ {
+ if (_subscribed) return;
+
+ var subscriber = await _connectionFactory.GetSubscriberAsync(cancellationToken).ConfigureAwait(false);
+ _subscription = await subscriber.SubscribeAsync(RedisChannel.Literal(NotificationChannel)).ConfigureAwait(false);
+ _subscription.OnMessage(_ =>
+ {
+ try { _notificationSignal.Release(); }
+ catch (SemaphoreFullException) { /* already signaled */ }
+ });
+ _subscribed = true;
+
+ _logger?.LogDebug("Subscribed to queue notifications on channel {Channel}", NotificationChannel);
+ }
+ finally
+ {
+ _subscriptionInitLock.Release();
+ }
+ }
+
#pragma warning disable CS1998
public async ValueTask DisposeAsync()
{
@@ -407,6 +460,15 @@ public sealed class ValkeyMessageQueue : IMessageQueue, IAsy
}
_disposed = true;
+
+ if (_subscription is not null)
+ {
+ try { _subscription.Unsubscribe(); }
+ catch { /* best-effort cleanup */ }
+ }
+
+ _notificationSignal.Dispose();
+ _subscriptionInitLock.Dispose();
_groupInitLock.Dispose();
}
@@ -637,6 +699,20 @@ public sealed class ValkeyMessageQueue : IMessageQueue, IAsy
}
var result = await database.ExecuteAsync("XADD", [.. args]).ConfigureAwait(false);
+
+ // Notify subscribers that new data is available (fire-and-forget).
+ try
+ {
+ await database.PublishAsync(
+ RedisChannel.Literal($"notify:q:{stream}"),
+ "1",
+ CommandFlags.FireAndForget).ConfigureAwait(false);
+ }
+ catch
+ {
+ // Best-effort notification; consumers will still poll on timeout fallback.
+ }
+
return result!.ToString()!;
}
diff --git a/src/Router/__Libraries/StellaOps.Messaging/Abstractions/INotifiableQueue.cs b/src/Router/__Libraries/StellaOps.Messaging/Abstractions/INotifiableQueue.cs
new file mode 100644
index 000000000..b56906ebb
--- /dev/null
+++ b/src/Router/__Libraries/StellaOps.Messaging/Abstractions/INotifiableQueue.cs
@@ -0,0 +1,18 @@
+namespace StellaOps.Messaging.Abstractions;
+
+///
+/// Optional interface for queues that support efficient notification-based wakeup
+/// instead of busy-wait polling. When the underlying transport supports it (e.g. Valkey Pub/Sub),
+/// consumers await a signal rather than spinning with Task.Delay.
+///
+public interface INotifiableQueue
+{
+ ///
+ /// Waits for a notification that new messages may be available.
+ /// Returns immediately if a notification has already been received since the last wait.
+ /// Falls back to returning after if no notification arrives.
+ ///
+ /// Maximum time to wait before returning (fallback for missed notifications).
+ /// Cancellation token.
+ Task WaitForNotificationAsync(TimeSpan timeout, CancellationToken cancellationToken);
+}
diff --git a/src/Router/__Libraries/StellaOps.Messaging/Options/EventStreamOptions.cs b/src/Router/__Libraries/StellaOps.Messaging/Options/EventStreamOptions.cs
index ae035470c..8edb26210 100644
--- a/src/Router/__Libraries/StellaOps.Messaging/Options/EventStreamOptions.cs
+++ b/src/Router/__Libraries/StellaOps.Messaging/Options/EventStreamOptions.cs
@@ -23,10 +23,11 @@ public sealed class EventStreamOptions
public bool ApproximateTrimming { get; set; } = true;
///
- /// Gets or sets the polling interval for subscription (when applicable).
- /// Default is 100ms.
+ /// Gets or sets the fallback timeout for subscription polling.
+ /// When Pub/Sub notifications are available, this acts as a safety-net timeout
+ /// in case a notification is missed. Default is 30 seconds.
///
- public TimeSpan PollInterval { get; set; } = TimeSpan.FromMilliseconds(100);
+ public TimeSpan PollInterval { get; set; } = TimeSpan.FromSeconds(30);
///
/// Gets or sets the idempotency window for duplicate detection.
diff --git a/src/Router/__Libraries/StellaOps.Microservice/StellaMicroserviceOptions.cs b/src/Router/__Libraries/StellaOps.Microservice/StellaMicroserviceOptions.cs
index 30addf820..40f0d1c6d 100644
--- a/src/Router/__Libraries/StellaOps.Microservice/StellaMicroserviceOptions.cs
+++ b/src/Router/__Libraries/StellaOps.Microservice/StellaMicroserviceOptions.cs
@@ -52,9 +52,9 @@ public sealed partial class StellaMicroserviceOptions
///
/// Gets or sets the heartbeat interval.
- /// Default: 10 seconds.
+ /// Default: 45 seconds.
///
- public TimeSpan HeartbeatInterval { get; set; } = TimeSpan.FromSeconds(10);
+ public TimeSpan HeartbeatInterval { get; set; } = TimeSpan.FromSeconds(45);
///
/// Gets or sets the maximum reconnect backoff.
diff --git a/src/Router/__Libraries/StellaOps.Router.AspNet/StellaRouterIntegrationHelper.cs b/src/Router/__Libraries/StellaOps.Router.AspNet/StellaRouterIntegrationHelper.cs
index ae69a7735..94d1627a1 100644
--- a/src/Router/__Libraries/StellaOps.Router.AspNet/StellaRouterIntegrationHelper.cs
+++ b/src/Router/__Libraries/StellaOps.Router.AspNet/StellaRouterIntegrationHelper.cs
@@ -455,7 +455,7 @@ public static class StellaRouterIntegrationHelper
NormalizeDuration(destination, $"{destinationSection}:RequestTimeout", TimeSpan.FromSeconds(30));
NormalizeDuration(destination, $"{destinationSection}:LeaseDuration", TimeSpan.FromMinutes(5));
- NormalizeDuration(destination, $"{destinationSection}:HeartbeatInterval", TimeSpan.FromSeconds(10));
+ NormalizeDuration(destination, $"{destinationSection}:HeartbeatInterval", TimeSpan.FromSeconds(45));
}
private static void NormalizeDuration(
diff --git a/src/Router/__Libraries/StellaOps.Router.AspNet/StellaRouterOptions.cs b/src/Router/__Libraries/StellaOps.Router.AspNet/StellaRouterOptions.cs
index 416f6e16e..9c958de33 100644
--- a/src/Router/__Libraries/StellaOps.Router.AspNet/StellaRouterOptions.cs
+++ b/src/Router/__Libraries/StellaOps.Router.AspNet/StellaRouterOptions.cs
@@ -99,9 +99,9 @@ public sealed class StellaRouterOptions
///
/// Heartbeat interval for health reporting.
- /// Default: 10 seconds.
+ /// Default: 45 seconds.
///
- public TimeSpan HeartbeatInterval { get; set; } = TimeSpan.FromSeconds(10);
+ public TimeSpan HeartbeatInterval { get; set; } = TimeSpan.FromSeconds(45);
///
/// Initial reconnect backoff delay.
diff --git a/src/Router/__Libraries/StellaOps.Router.AspNet/StellaRouterOptionsBase.cs b/src/Router/__Libraries/StellaOps.Router.AspNet/StellaRouterOptionsBase.cs
index a36d12bff..9d2b0d146 100644
--- a/src/Router/__Libraries/StellaOps.Router.AspNet/StellaRouterOptionsBase.cs
+++ b/src/Router/__Libraries/StellaOps.Router.AspNet/StellaRouterOptionsBase.cs
@@ -39,9 +39,9 @@ public class StellaRouterOptionsBase
///
/// Heartbeat interval in seconds for health reporting.
- /// Default: 10 seconds.
+ /// Default: 45 seconds.
///
- public int HeartbeatIntervalSeconds { get; set; } = 10;
+ public int HeartbeatIntervalSeconds { get; set; } = 45;
///
/// Service trust mode for gateway-enforced authorization semantics.
diff --git a/src/Router/__Libraries/StellaOps.Router.Gateway/Configuration/HealthOptions.cs b/src/Router/__Libraries/StellaOps.Router.Gateway/Configuration/HealthOptions.cs
index f29663a6f..19f0a5a37 100644
--- a/src/Router/__Libraries/StellaOps.Router.Gateway/Configuration/HealthOptions.cs
+++ b/src/Router/__Libraries/StellaOps.Router.Gateway/Configuration/HealthOptions.cs
@@ -12,21 +12,23 @@ public sealed class HealthOptions
///
/// Gets or sets the threshold after which a connection is considered stale (no heartbeat).
- /// Default: 30 seconds.
+ /// Should be at least 3x the heartbeat interval (45s default).
+ /// Default: 135 seconds.
///
- public TimeSpan StaleThreshold { get; set; } = TimeSpan.FromSeconds(30);
+ public TimeSpan StaleThreshold { get; set; } = TimeSpan.FromSeconds(135);
///
/// Gets or sets the threshold after which a connection is considered degraded.
- /// Default: 15 seconds.
+ /// Should be at least 2x the heartbeat interval (45s default).
+ /// Default: 90 seconds.
///
- public TimeSpan DegradedThreshold { get; set; } = TimeSpan.FromSeconds(15);
+ public TimeSpan DegradedThreshold { get; set; } = TimeSpan.FromSeconds(90);
///
/// Gets or sets the interval at which to check for stale connections.
- /// Default: 5 seconds.
+ /// Default: 15 seconds.
///
- public TimeSpan CheckInterval { get; set; } = TimeSpan.FromSeconds(5);
+ public TimeSpan CheckInterval { get; set; } = TimeSpan.FromSeconds(15);
///
/// Gets or sets the number of ping measurements to keep for averaging.
diff --git a/src/Router/__Libraries/StellaOps.Router.Transport.InMemory/InMemoryTransportOptions.cs b/src/Router/__Libraries/StellaOps.Router.Transport.InMemory/InMemoryTransportOptions.cs
index 6c655f578..e938b60e6 100644
--- a/src/Router/__Libraries/StellaOps.Router.Transport.InMemory/InMemoryTransportOptions.cs
+++ b/src/Router/__Libraries/StellaOps.Router.Transport.InMemory/InMemoryTransportOptions.cs
@@ -25,13 +25,13 @@ public sealed class InMemoryTransportOptions
///
/// Gets or sets the heartbeat interval.
- /// Default: 10 seconds.
+ /// Default: 45 seconds.
///
- public TimeSpan HeartbeatInterval { get; set; } = TimeSpan.FromSeconds(10);
+ public TimeSpan HeartbeatInterval { get; set; } = TimeSpan.FromSeconds(45);
///
/// Gets or sets the heartbeat timeout (time since last heartbeat before connection is considered unhealthy).
- /// Default: 30 seconds.
+ /// Default: 135 seconds (3x heartbeat interval).
///
- public TimeSpan HeartbeatTimeout { get; set; } = TimeSpan.FromSeconds(30);
+ public TimeSpan HeartbeatTimeout { get; set; } = TimeSpan.FromSeconds(135);
}
diff --git a/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/Extensions/QueueWaitExtensions.cs b/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/Extensions/QueueWaitExtensions.cs
new file mode 100644
index 000000000..f9b1c0bba
--- /dev/null
+++ b/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/Extensions/QueueWaitExtensions.cs
@@ -0,0 +1,38 @@
+using StellaOps.Messaging.Abstractions;
+
+namespace StellaOps.Router.Transport.Messaging.Extensions;
+
+///
+/// Extension to efficiently await new messages on a queue.
+/// Uses Pub/Sub wakeup when available,
+/// falls back to a short delay for non-notifiable queue implementations.
+///
+internal static class QueueWaitExtensions
+{
+ ///
+ /// Default fallback timeout when the queue supports Pub/Sub notifications.
+ /// The wait returns early on notification; this is only a safety net.
+ ///
+ private static readonly TimeSpan NotifiableTimeout = TimeSpan.FromSeconds(30);
+
+ ///
+ /// Fallback delay for queues that do not implement .
+ ///
+ private static readonly TimeSpan PollingFallback = TimeSpan.FromSeconds(1);
+
+ ///
+ /// Waits for new messages to become available on the queue.
+ ///
+ public static Task WaitForMessagesAsync(
+ this IMessageQueue queue,
+ CancellationToken cancellationToken)
+ where TMessage : class
+ {
+ if (queue is INotifiableQueue notifiable)
+ {
+ return notifiable.WaitForNotificationAsync(NotifiableTimeout, cancellationToken);
+ }
+
+ return Task.Delay(PollingFallback, cancellationToken);
+ }
+}
diff --git a/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportClient.cs b/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportClient.cs
index 704bfe13b..fd8d4bdf5 100644
--- a/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportClient.cs
+++ b/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportClient.cs
@@ -4,6 +4,7 @@ using Microsoft.Extensions.Options;
using StellaOps.Messaging;
using StellaOps.Messaging.Abstractions;
using StellaOps.Router.Common.Abstractions;
+using StellaOps.Router.Transport.Messaging.Extensions;
using StellaOps.Router.Common.Enums;
using StellaOps.Router.Common.Models;
using StellaOps.Router.Transport.Messaging.Options;
@@ -202,9 +203,10 @@ public sealed class MessagingTransportClient : ITransportClient, IMicroserviceTr
}
}
+ // Wait for Pub/Sub notification instead of busy-polling.
if (leases.Count == 0)
{
- await Task.Delay(100, cancellationToken);
+ await _responseQueue.WaitForMessagesAsync(cancellationToken);
}
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
@@ -265,9 +267,10 @@ public sealed class MessagingTransportClient : ITransportClient, IMicroserviceTr
}
}
+ // Wait for Pub/Sub notification instead of busy-polling.
if (leases.Count == 0)
{
- await Task.Delay(100, cancellationToken);
+ await _serviceIncomingQueue.WaitForMessagesAsync(cancellationToken);
}
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
diff --git a/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportServer.cs b/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportServer.cs
index c6f5e25b9..c7f0dd219 100644
--- a/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportServer.cs
+++ b/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/MessagingTransportServer.cs
@@ -4,6 +4,7 @@ using Microsoft.Extensions.Options;
using StellaOps.Messaging;
using StellaOps.Messaging.Abstractions;
using StellaOps.Router.Common.Abstractions;
+using StellaOps.Router.Transport.Messaging.Extensions;
using StellaOps.Router.Common.Enums;
using StellaOps.Router.Common.Models;
using StellaOps.Router.Transport.Messaging.Options;
@@ -169,10 +170,10 @@ public sealed class MessagingTransportServer : ITransportServer, IDisposable
}
}
- // Small delay if no messages
+ // Wait for Pub/Sub notification instead of busy-polling.
if (leases.Count == 0)
{
- await Task.Delay(100, cancellationToken);
+ await _requestQueue.WaitForMessagesAsync(cancellationToken);
}
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
@@ -213,9 +214,10 @@ public sealed class MessagingTransportServer : ITransportServer, IDisposable
}
}
+ // Wait for Pub/Sub notification instead of busy-polling.
if (leases.Count == 0)
{
- await Task.Delay(100, cancellationToken);
+ await _responseQueue.WaitForMessagesAsync(cancellationToken);
}
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
diff --git a/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/Options/MessagingTransportOptions.cs b/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/Options/MessagingTransportOptions.cs
index c9ad76dac..17f097ff0 100644
--- a/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/Options/MessagingTransportOptions.cs
+++ b/src/Router/__Libraries/StellaOps.Router.Transport.Messaging/Options/MessagingTransportOptions.cs
@@ -55,8 +55,9 @@ public class MessagingTransportOptions
///
/// Gets or sets the heartbeat interval.
+ /// Default: 45 seconds.
///
- public TimeSpan HeartbeatInterval { get; set; } = TimeSpan.FromSeconds(10);
+ public TimeSpan HeartbeatInterval { get; set; } = TimeSpan.FromSeconds(45);
///
/// Gets or sets the dead letter queue suffix.
diff --git a/src/Router/__Tests/StellaOps.Router.AspNet.Tests/StellaRouterOptionsTests.cs b/src/Router/__Tests/StellaOps.Router.AspNet.Tests/StellaRouterOptionsTests.cs
index a91388eb3..a50a49431 100644
--- a/src/Router/__Tests/StellaOps.Router.AspNet.Tests/StellaRouterOptionsTests.cs
+++ b/src/Router/__Tests/StellaOps.Router.AspNet.Tests/StellaRouterOptionsTests.cs
@@ -41,7 +41,7 @@ public sealed class StellaRouterOptionsTests
Assert.Equal(AuthorizationMappingStrategy.Hybrid, options.AuthorizationMapping);
Assert.Equal(MissingAuthorizationBehavior.WarnAndAllow, options.OnMissingAuthorization);
Assert.Equal(TimeSpan.FromSeconds(30), options.DefaultTimeout);
- Assert.Equal(TimeSpan.FromSeconds(10), options.HeartbeatInterval);
+ Assert.Equal(TimeSpan.FromSeconds(45), options.HeartbeatInterval);
}
[Fact]
diff --git a/src/Router/__Tests/StellaOps.Router.Transport.InMemory.Tests/InMemoryTransportOptionsTests.cs b/src/Router/__Tests/StellaOps.Router.Transport.InMemory.Tests/InMemoryTransportOptionsTests.cs
index e52e1d171..83ecfa9a9 100644
--- a/src/Router/__Tests/StellaOps.Router.Transport.InMemory.Tests/InMemoryTransportOptionsTests.cs
+++ b/src/Router/__Tests/StellaOps.Router.Transport.InMemory.Tests/InMemoryTransportOptionsTests.cs
@@ -43,24 +43,24 @@ public sealed class InMemoryTransportOptionsTests
[Trait("Category", TestCategories.Unit)]
[Fact]
- public void Constructor_HeartbeatInterval_Is10Seconds()
+ public void Constructor_HeartbeatInterval_Is45Seconds()
{
// Arrange & Act
var options = new InMemoryTransportOptions();
// Assert
- options.HeartbeatInterval.Should().Be(TimeSpan.FromSeconds(10));
+ options.HeartbeatInterval.Should().Be(TimeSpan.FromSeconds(45));
}
[Trait("Category", TestCategories.Unit)]
[Fact]
- public void Constructor_HeartbeatTimeout_Is30Seconds()
+ public void Constructor_HeartbeatTimeout_Is135Seconds()
{
// Arrange & Act
var options = new InMemoryTransportOptions();
// Assert
- options.HeartbeatTimeout.Should().Be(TimeSpan.FromSeconds(30));
+ options.HeartbeatTimeout.Should().Be(TimeSpan.FromSeconds(135));
}
#endregion