perf(site-runtime): coalesce native-alarm mirror persistence into batched flushes (P4)

This commit is contained in:
Joseph Doherty
2026-07-09 01:05:20 -04:00
parent d2feb92bfd
commit 326d945d85
3 changed files with 154 additions and 7 deletions
@@ -506,6 +506,56 @@ public class SiteStorageService
await command.ExecuteNonQueryAsync();
}
/// <summary>
/// Batch counterpart of <see cref="UpsertNativeAlarmAsync"/> (P4): upserts a set of mirrored
/// native alarm conditions for one instance/source in a SINGLE connection + transaction with
/// one prepared command re-bound per row. Used by the NativeAlarmActor's coalesced flush so an
/// alarm storm collapses into one batched write instead of a write per transition.
/// </summary>
/// <param name="instanceName">Unique name of the instance owning the alarms.</param>
/// <param name="sourceCanonicalName">Canonical name of the source binding.</param>
/// <param name="rows">The conditions to upsert (source reference, serialized condition, transition time).</param>
/// <returns>A task that completes when all rows have been committed.</returns>
public async Task UpsertNativeAlarmsAsync(
string instanceName, string sourceCanonicalName,
IReadOnlyList<(string SourceReference, string ConditionJson, DateTimeOffset LastTransitionAt)> rows)
{
if (rows.Count == 0)
return;
await using var connection = new SqliteConnection(_connectionString);
await connection.OpenAsync();
await using var transaction = (SqliteTransaction)await connection.BeginTransactionAsync();
await using var command = connection.CreateCommand();
command.Transaction = transaction;
command.CommandText = @"
INSERT INTO native_alarm_state
(instance_unique_name, source_canonical_name, source_reference, condition_json, last_transition_at)
VALUES (@name, @source, @ref, @json, @at)
ON CONFLICT(instance_unique_name, source_canonical_name, source_reference) DO UPDATE SET
condition_json = excluded.condition_json,
last_transition_at = excluded.last_transition_at";
var pName = command.Parameters.Add("@name", SqliteType.Text);
var pSource = command.Parameters.Add("@source", SqliteType.Text);
var pRef = command.Parameters.Add("@ref", SqliteType.Text);
var pJson = command.Parameters.Add("@json", SqliteType.Text);
var pAt = command.Parameters.Add("@at", SqliteType.Text);
pName.Value = instanceName;
pSource.Value = sourceCanonicalName;
foreach (var row in rows)
{
pRef.Value = row.SourceReference;
pJson.Value = row.ConditionJson;
pAt.Value = row.LastTransitionAt.ToString("O");
await command.ExecuteNonQueryAsync();
}
await transaction.CommitAsync();
}
/// <summary>
/// Removes a single mirrored native alarm condition (e.g. a return-to-normal that drops out of retention).
/// </summary>