feat(batch27): implement jetstream config validation and error tail

This commit is contained in:
Joseph Doherty
2026-02-28 21:15:57 -05:00
parent 68f32c7b85
commit 5b2d32c503
6 changed files with 214 additions and 0 deletions

View File

@@ -7,6 +7,7 @@ namespace ZB.MOM.NatsNet.Server;
public sealed partial class NatsServer
{
private const string JetStreamStoreDir = "jetstream";
private const long JetStreamMaxMemDefault = 1024L * 1024L * 256L;
public Exception? EnableJetStream(JetStreamConfig? config)
{
@@ -495,6 +496,81 @@ public sealed partial class NatsServer
null);
}
internal JetStreamConfig DynJetStreamConfig(string storeDir, long maxStore, long maxMem)
{
var cfg = new JetStreamConfig();
if (!string.IsNullOrWhiteSpace(storeDir))
{
cfg.StoreDir = Path.Combine(storeDir, JetStreamStoreDir);
}
else
{
cfg.StoreDir = Path.Combine(Path.GetTempPath(), "nats", JetStreamStoreDir);
Warnf("Temporary storage directory used, data could be lost on system reboot");
}
var opts = GetOpts();
cfg.Strict = !opts.NoJetStreamStrict;
cfg.SyncInterval = opts.SyncInterval;
cfg.SyncAlways = opts.SyncAlways;
cfg.MaxStore = opts.MaxStoreSet && maxStore >= 0
? maxStore
: DiskAvailability.DiskAvailable(cfg.StoreDir);
if (opts.MaxMemSet && maxMem >= 0)
{
cfg.MaxMemory = maxMem;
}
else
{
var totalAvailable = GC.GetGCMemoryInfo().TotalAvailableMemoryBytes;
cfg.MaxMemory = totalAvailable > 0 && totalAvailable < long.MaxValue
? totalAvailable / 4 * 3
: JetStreamMaxMemDefault;
}
return cfg;
}
internal void ResourcesExceededError(StorageType storeType)
{
var didAlert = false;
lock (_resourceErrorLock)
{
var now = DateTime.UtcNow;
if (now - _resourceErrorLastUtc > TimeSpan.FromSeconds(10))
{
var storeName = storeType switch
{
StorageType.MemoryStorage => "memory",
StorageType.FileStorage => "file",
_ => storeType.ToString().ToLowerInvariant(),
};
Errorf("JetStream {0} resource limits exceeded for server", storeName);
_resourceErrorLastUtc = now;
didAlert = true;
}
}
if (!didAlert)
return;
var js = GetJetStreamState();
if (js?.Cluster is JetStreamCluster { Meta: not null } cluster)
cluster.Meta.StepDown();
}
internal void HandleWritePermissionError()
{
if (!JetStreamEnabled())
return;
Errorf("File system permission denied while writing, disabling JetStream");
_ = Task.Run(() => DisableJetStream());
}
internal JetStreamEngine? GetJetStream() =>
_jetStream == null ? null : new JetStreamEngine(_jetStream);