fix(historian): ContinuousHistorization CommitMode code default is PerEntry, matching appsettings/docker-dev/fallback (lmxopcua#776)
v2-ci / unit-tests (push) Has been cancelled
v2-ci / unit-tests (push) Has been cancelled
The Lane H2 remediation made Periodic(100 ms) the options-class default, but appsettings.json, docker-dev and Program.cs's bad-value fallback all used PerEntry, so effective behaviour never changed and the docs contradicted the shipped config. The options default is now PerEntry; Periodic stays opt-in (<= CommitIntervalMs of crash loss in exchange for throughput). Program.cs now uses ContinuousHistorizationOptions.ResolveCommitMode() so the fallback shares the single DefaultCommitMode constant. docs/Historian.md updated. Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
@@ -315,10 +315,7 @@ if (hasDriver)
|
||||
// outbox depth/dropped gauges here (once, on first resolution) keeps the live instance behind them.
|
||||
builder.Services.AddSingleton<IHistorizationOutbox>(_ =>
|
||||
{
|
||||
var commitMode = Enum.TryParse<HistorizationCommitMode>(
|
||||
continuousHistorizationOptions.CommitMode, ignoreCase: true, out var parsedMode)
|
||||
? parsedMode
|
||||
: HistorizationCommitMode.PerEntry;
|
||||
var commitMode = continuousHistorizationOptions.ResolveCommitMode();
|
||||
var outbox = new FasterLogHistorizationOutbox(
|
||||
continuousHistorizationOptions.OutboxPath,
|
||||
commitMode,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Runtime.Historian;
|
||||
|
||||
@@ -38,20 +39,28 @@ public sealed class ContinuousHistorizationOptions
|
||||
public string OutboxPath { get; init; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Outbox commit cadence: <c>Periodic</c> (the default) commits on a background timer every
|
||||
/// <see cref="CommitIntervalMs"/> ms (100 ms by default — a crash can lose at most the last interval of captured
|
||||
/// values); <c>PerEntry</c> fsyncs before each append returns (no loss window, one fsync per append). Parsed
|
||||
/// case-insensitively against <c>HistorizationCommitMode</c>.
|
||||
/// Outbox commit cadence: <c>PerEntry</c> (the default, and what the shipped <c>appsettings.json</c>, docker-dev
|
||||
/// and the unparseable-value fallback all use) fsyncs before each append returns — no loss window; <c>Periodic</c>
|
||||
/// is the opt-in throughput mode that commits on a background timer every <see cref="CommitIntervalMs"/> ms
|
||||
/// (100 ms by default), so a crash can lose at most the last interval of captured values. Parsed
|
||||
/// case-insensitively against <c>HistorizationCommitMode</c>; see <see cref="ResolveCommitMode"/>.
|
||||
/// <para>
|
||||
/// <b>Why Periodic.</b> Under <c>PerEntry</c> every ingest append waits for an fsync, so ingestion is capped at
|
||||
/// <c>1 / fsync_latency</c> appends per second (50 drivers × 1 Hz on a 10 ms-fsync disk kept the recorder half
|
||||
/// busy; at 100+ bursts/s it fell behind for good). The recorder now appends off its mailbox and coalesces
|
||||
/// every burst waiting behind a slow append into one group commit, which helps <c>PerEntry</c> too — but it is
|
||||
/// still one fsync per group on the critical path. <c>PerEntry</c> remains available where no loss window is
|
||||
/// acceptable.
|
||||
/// <b>Trade-off.</b> Under <c>PerEntry</c> every ingest append waits for an fsync, so ingestion is capped at
|
||||
/// <c>1 / fsync_latency</c> appends per second — but the recorder appends off its mailbox and coalesces
|
||||
/// every burst waiting behind a slow append into one group commit, so it is one fsync per group, not per
|
||||
/// value. Set <c>Periodic</c> explicitly where higher ingest throughput matters more than a bounded
|
||||
/// (<c><= CommitIntervalMs</c>) crash-loss window.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public string CommitMode { get; init; } = "Periodic";
|
||||
public string CommitMode { get; init; } = DefaultCommitMode.ToString();
|
||||
|
||||
/// <summary>The commit mode used when <see cref="CommitMode"/> is not set or cannot be parsed.</summary>
|
||||
public const HistorizationCommitMode DefaultCommitMode = HistorizationCommitMode.PerEntry;
|
||||
|
||||
/// <summary>Parses <see cref="CommitMode"/> case-insensitively; an unparseable value falls back to
|
||||
/// <see cref="DefaultCommitMode"/> so the fallback always agrees with the options default.</summary>
|
||||
public HistorizationCommitMode ResolveCommitMode() =>
|
||||
Enum.TryParse<HistorizationCommitMode>(CommitMode, ignoreCase: true, out var mode) ? mode : DefaultCommitMode;
|
||||
|
||||
/// <summary>Periodic-mode commit cadence in milliseconds; must be positive when
|
||||
/// <see cref="CommitMode"/> is <c>Periodic</c>. Ignored under <c>PerEntry</c>.</summary>
|
||||
|
||||
Reference in New Issue
Block a user