feat(auditlog): thread ParentExecutionId through S&F for retry-loop cached rows
The store-and-forward retry loop emits the per-attempt and terminal cached audit rows (ApiCallCached/DbWriteCached Attempted, CachedResolve) via CachedCallLifecycleBridge from a CachedCallAttemptContext, not from the script context. The ExecutionId rollout (Task 4) already threaded ExecutionId and SourceScript through this path; ParentExecutionId — the spawning inbound-API request's ExecutionId — was not, so those retry-loop rows had ParentExecutionId = null even for an inbound-API-routed run. Thread it additively as a sibling at every carry point ExecutionId passes through: - StoreAndForwardMessage gains ParentExecutionId (Guid?). - StoreAndForwardStorage adds a nullable parent_execution_id column via the same idempotent PRAGMA-probed ALTER TABLE migration; rows persisted by an older build read back null (back-compat). The defensive Guid.TryParse read helper (ParseExecutionId) is renamed ParseGuidColumn and reused for both columns so a corrupt value cannot abort the retry sweep. - StoreAndForwardService.EnqueueAsync gains an optional parentExecutionId param, stamped onto the buffered message and surfaced on the CachedCallAttemptContext built in the retry loop. - CachedCallAttemptContext gains ParentExecutionId. - CachedCallLifecycleBridge.BuildPacket sets AuditEvent.ParentExecutionId from the context, beside the existing ExecutionId. - IExternalSystemClient.CachedCallAsync / IDatabaseGateway.CachedWriteAsync gain an optional parentExecutionId param; ScriptRuntimeContext's CachedCall / CachedWrite helpers pass _parentExecutionId. All threading is additive — ParentExecutionId is Guid? everywhere, null for non-routed runs, and old buffered S&F rows still deserialize with the new field null.
This commit is contained in:
@@ -71,6 +71,16 @@ public interface ICachedCallLifecycleObserver
|
||||
/// rows carry the same <c>SourceScript</c> provenance the script-side cached
|
||||
/// rows already do. <c>null</c> when not known.
|
||||
/// </param>
|
||||
/// <param name="ParentExecutionId">
|
||||
/// Audit Log #23 (ParentExecutionId Task 6): the <c>ExecutionId</c> of the
|
||||
/// inbound-API request that spawned the originating script execution,
|
||||
/// threaded through the store-and-forward buffer alongside
|
||||
/// <paramref name="ExecutionId"/>. The audit bridge stamps it onto the
|
||||
/// retry-loop <c>ApiCallCached</c>/<c>DbWriteCached</c> Attempted and
|
||||
/// <c>CachedResolve</c> rows so they correlate back to the spawning run.
|
||||
/// <c>null</c> for a non-routed run and for rows buffered before Task 6
|
||||
/// (back-compat).
|
||||
/// </param>
|
||||
public sealed record CachedCallAttemptContext(
|
||||
TrackedOperationId TrackedOperationId,
|
||||
string Channel,
|
||||
@@ -85,7 +95,8 @@ public sealed record CachedCallAttemptContext(
|
||||
int? DurationMs,
|
||||
string? SourceInstanceId,
|
||||
Guid? ExecutionId = null,
|
||||
string? SourceScript = null);
|
||||
string? SourceScript = null,
|
||||
Guid? ParentExecutionId = null);
|
||||
|
||||
/// <summary>
|
||||
/// Coarse outcome of one cached-call delivery attempt, observed from inside
|
||||
|
||||
@@ -40,6 +40,14 @@ public interface IDatabaseGateway
|
||||
/// threaded onto the buffered S&F message alongside
|
||||
/// <paramref name="executionId"/>. <c>null</c> when not known.
|
||||
/// </param>
|
||||
/// <param name="parentExecutionId">
|
||||
/// Audit Log #23 (ParentExecutionId Task 6): the <c>ExecutionId</c> of the
|
||||
/// inbound-API request that spawned the originating script execution.
|
||||
/// When the write is buffered on a transient failure this is threaded onto
|
||||
/// the S&F message alongside <paramref name="executionId"/> so the
|
||||
/// retry-loop cached-write audit rows carry it. <c>null</c> for a
|
||||
/// non-routed run.
|
||||
/// </param>
|
||||
Task CachedWriteAsync(
|
||||
string connectionName,
|
||||
string sql,
|
||||
@@ -48,5 +56,6 @@ public interface IDatabaseGateway
|
||||
CancellationToken cancellationToken = default,
|
||||
TrackedOperationId? trackedOperationId = null,
|
||||
Guid? executionId = null,
|
||||
string? sourceScript = null);
|
||||
string? sourceScript = null,
|
||||
Guid? parentExecutionId = null);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,14 @@ public interface IExternalSystemClient
|
||||
/// threaded onto the buffered S&F message alongside
|
||||
/// <paramref name="executionId"/>. <c>null</c> when not known.
|
||||
/// </param>
|
||||
/// <param name="parentExecutionId">
|
||||
/// Audit Log #23 (ParentExecutionId Task 6): the <c>ExecutionId</c> of the
|
||||
/// inbound-API request that spawned the originating script execution.
|
||||
/// When the call is buffered on a transient failure this is threaded onto
|
||||
/// the S&F message alongside <paramref name="executionId"/> so the
|
||||
/// retry-loop cached-call audit rows carry it. <c>null</c> for a non-routed
|
||||
/// run.
|
||||
/// </param>
|
||||
Task<ExternalCallResult> CachedCallAsync(
|
||||
string systemName,
|
||||
string methodName,
|
||||
@@ -49,7 +57,8 @@ public interface IExternalSystemClient
|
||||
CancellationToken cancellationToken = default,
|
||||
TrackedOperationId? trackedOperationId = null,
|
||||
Guid? executionId = null,
|
||||
string? sourceScript = null);
|
||||
string? sourceScript = null,
|
||||
Guid? parentExecutionId = null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user