feat: add jetstream mirror and source orchestration

This commit is contained in:
Joseph Doherty
2026-02-23 06:10:41 -05:00
parent d3aad48096
commit f1d3c19594
6 changed files with 128 additions and 0 deletions

View File

@@ -61,6 +61,18 @@ internal sealed class JetStreamApiFixture : IAsyncDisposable
return fixture;
}
public static async Task<JetStreamApiFixture> StartWithMirrorSetupAsync()
{
var fixture = await StartWithStreamAsync("ORDERS", "orders.*");
_ = fixture._streamManager.CreateOrUpdate(new StreamConfig
{
Name = "ORDERS_MIRROR",
Subjects = ["orders.mirror.*"],
Mirror = "ORDERS",
});
return fixture;
}
public Task<PubAck> PublishAndGetAckAsync(string subject, string payload, string? msgId = null, bool expectError = false)
{
if (_publisher.TryCapture(subject, Encoding.UTF8.GetBytes(payload), msgId, out var ack))
@@ -81,6 +93,11 @@ internal sealed class JetStreamApiFixture : IAsyncDisposable
throw new InvalidOperationException($"No stream matched subject '{subject}'.");
}
public Task<PubAck> PublishAndGetAckAsync(string streamName, string subject, string payload)
{
return PublishAndGetAckAsync(subject, payload);
}
public Task<JetStreamApiResponse> RequestLocalAsync(string subject, string payload)
{
return Task.FromResult(_router.Route(subject, Encoding.UTF8.GetBytes(payload)));
@@ -122,5 +139,17 @@ internal sealed class JetStreamApiFixture : IAsyncDisposable
return Task.FromResult(frame);
}
public async Task WaitForMirrorSyncAsync(string streamName)
{
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(2));
while (!timeout.IsCancellationRequested)
{
var state = await GetStreamStateAsync(streamName);
if (state.Messages > 0)
return;
await Task.Delay(25, timeout.Token).ContinueWith(_ => { }, TaskScheduler.Default);
}
}
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
}