perf(site-runtime): coalesce native-alarm mirror persistence into batched flushes (P4)
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user