feat: route publishes to jetstream with puback

This commit is contained in:
Joseph Doherty
2026-02-23 06:03:24 -05:00
parent 5f530de2e4
commit 95691fa9e7
6 changed files with 116 additions and 4 deletions

View File

@@ -0,0 +1,30 @@
namespace NATS.Server.JetStream.Publish;
public sealed class JetStreamPublisher
{
private readonly StreamManager _streamManager;
public JetStreamPublisher(StreamManager streamManager)
{
_streamManager = streamManager;
}
public bool TryCapture(string subject, ReadOnlyMemory<byte> payload, out PubAck ack)
{
var stream = _streamManager.FindBySubject(subject);
if (stream == null)
{
ack = new PubAck();
return false;
}
var seq = stream.Store.AppendAsync(subject, payload, default).GetAwaiter().GetResult();
ack = new PubAck
{
Stream = stream.Config.Name,
Seq = seq,
};
return true;
}
}

View File

@@ -0,0 +1,8 @@
namespace NATS.Server.JetStream.Publish;
public sealed class PubAck
{
public string Stream { get; init; } = string.Empty;
public ulong Seq { get; init; }
public int? ErrorCode { get; init; }
}

View File

@@ -8,6 +8,7 @@ using System.Text.Json;
using System.Threading.Channels;
using Microsoft.Extensions.Logging;
using NATS.Server.Auth;
using NATS.Server.JetStream.Publish;
using NATS.Server.Protocol;
using NATS.Server.Subscriptions;
using NATS.Server.Tls;
@@ -103,6 +104,7 @@ public sealed class NatsClient : IDisposable
public bool InfoAlreadySent { get; set; }
public IReadOnlyDictionary<string, Subscription> Subscriptions => _subs;
public PubAck? LastJetStreamPubAck { get; private set; }
public NatsClient(ulong id, Stream stream, Socket socket, NatsOptions options, ServerInfo serverInfo,
AuthService authService, byte[]? nonce, ILogger logger, ServerStats serverStats,
@@ -593,6 +595,11 @@ public sealed class NatsClient : IDisposable
Router?.ProcessMessage(cmd.Subject!, cmd.ReplyTo, headers, payload, this);
}
public void RecordJetStreamPubAck(PubAck ack)
{
LastJetStreamPubAck = ack;
}
private void SendInfo()
{
// Use the cached INFO bytes from the server when there is no per-connection

View File

@@ -12,6 +12,7 @@ using NATS.Server.Configuration;
using NATS.Server.Gateways;
using NATS.Server.JetStream;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Publish;
using NATS.Server.LeafNodes;
using NATS.Server.Monitoring;
using NATS.Server.Protocol;
@@ -49,6 +50,8 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
private readonly LeafNodeManager? _leafNodeManager;
private readonly JetStreamService? _jetStreamService;
private readonly JetStreamApiRouter? _jetStreamApiRouter;
private readonly StreamManager? _jetStreamStreamManager;
private readonly JetStreamPublisher? _jetStreamPublisher;
private Socket? _listener;
private Socket? _wsListener;
private readonly TaskCompletionSource _wsAcceptLoopExited = new(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -94,6 +97,14 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
public IEnumerable<Auth.Account> GetAccounts() => _accounts.Values;
public bool HasRemoteInterest(string subject) => _globalAccount.SubList.HasRemoteInterest(subject);
public bool TryCaptureJetStreamPublish(string subject, ReadOnlyMemory<byte> payload, out PubAck ack)
{
if (_jetStreamPublisher != null)
return _jetStreamPublisher.TryCapture(subject, payload, out ack);
ack = new PubAck();
return false;
}
public Task WaitForReadyAsync() => _listeningStarted.Task;
@@ -329,8 +340,10 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
if (options.JetStream != null)
{
_jetStreamStreamManager = new StreamManager();
_jetStreamService = new JetStreamService(options.JetStream);
_jetStreamApiRouter = new JetStreamApiRouter();
_jetStreamApiRouter = new JetStreamApiRouter(_jetStreamStreamManager);
_jetStreamPublisher = new JetStreamPublisher(_jetStreamStreamManager);
}
if (options.HasTls)
@@ -746,6 +759,9 @@ public sealed class NatsServer : IMessageRouter, ISubListAccess, IDisposable
public void ProcessMessage(string subject, string? replyTo, ReadOnlyMemory<byte> headers,
ReadOnlyMemory<byte> payload, NatsClient sender)
{
if (TryCaptureJetStreamPublish(subject, payload, out var pubAck))
sender.RecordJetStreamPubAck(pubAck);
// Apply subject transforms
if (_subjectTransforms.Length > 0)
{