feat(inboundapi): mint inbound ExecutionId early, carry it as RouteToCallRequest.ParentExecutionId

This commit is contained in:
Joseph Doherty
2026-05-21 17:22:13 -04:00
parent 50430b9daa
commit d8453bfba2
8 changed files with 326 additions and 21 deletions
@@ -4,6 +4,7 @@ using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.Extensions.Logging;
using ScadaLink.Commons.Entities.InboundApi;
using ScadaLink.Commons.Messages.InboundApi;
using ScadaLink.Commons.Types;
namespace ScadaLink.InboundAPI;
@@ -156,12 +157,22 @@ public class InboundScriptExecutor
/// <summary>
/// Executes the script for the given method with the provided context.
/// </summary>
/// <param name="parentExecutionId">
/// Audit Log #23 (ParentExecutionId): the inbound API request's per-request
/// <c>ExecutionId</c> (minted early by <c>AuditWriteMiddleware</c> and stashed
/// on <c>HttpContext.Items</c>). When supplied, a routed
/// <c>Route.To(...).Call(...)</c> inside the script carries it as
/// <see cref="RouteToCallRequest.ParentExecutionId"/> so the spawned site
/// script execution points back at this inbound request. Null when the script
/// runs outside an inbound API request flow.
/// </param>
public async Task<InboundScriptResult> ExecuteAsync(
ApiMethod method,
IReadOnlyDictionary<string, object?> parameters,
RouteHelper route,
TimeSpan timeout,
CancellationToken cancellationToken = default)
CancellationToken cancellationToken = default,
Guid? parentExecutionId = null)
{
// InboundAPI-004: keep the timeout source and the request-abort source
// separable. A single linked CTS makes a genuine client disconnect
@@ -177,7 +188,14 @@ public class InboundScriptExecutor
// InboundAPI-016: bind the route helper to the method deadline so a
// routed Route.To(...).Call(...) inherits the method-level timeout
// without the script having to thread the context token by hand.
var context = new InboundScriptContext(parameters, route.WithDeadline(cts.Token), cts.Token);
//
// Audit Log #23 (ParentExecutionId): also bind the inbound request's
// ExecutionId so a routed call carries it as ParentExecutionId — the
// spawned site script execution points back at this inbound request.
var context = new InboundScriptContext(
parameters,
route.WithDeadline(cts.Token).WithParentExecutionId(parentExecutionId),
cts.Token);
if (!_scriptHandlers.TryGetValue(method.Name, out var handler))
{