fix(siteruntime): faulted expression-eval task clears _evalInFlight instead of killing the ScriptActor trigger (plan R2-03 T2)
This commit is contained in:
@@ -159,6 +159,10 @@ public class ScriptActor : ReceiveActor, IWithTimers
|
||||
|
||||
// Handle the off-dispatcher trigger-expression evaluation result (P1).
|
||||
Receive<ExpressionEvalResult>(HandleExpressionEvalResult);
|
||||
|
||||
// Handle a faulted off-dispatcher evaluation task (N2) — clears in-flight
|
||||
// instead of stranding the trigger with an unhandled Status.Failure.
|
||||
Receive<ExpressionEvalFailed>(HandleExpressionEvalFailed);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -310,7 +314,8 @@ public class ScriptActor : ReceiveActor, IWithTimers
|
||||
}
|
||||
}, CancellationToken.None, TaskCreationOptions.DenyChildAttach,
|
||||
ScriptExecutionScheduler.Shared(_options)).Unwrap().PipeTo(self,
|
||||
success: r => new ExpressionEvalResult(r));
|
||||
success: r => new ExpressionEvalResult(r),
|
||||
failure: ex => new ExpressionEvalFailed(ex));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -333,6 +338,18 @@ public class ScriptActor : ReceiveActor, IWithTimers
|
||||
if (_evalPending) { _evalPending = false; StartExpressionEvaluation(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a faulted off-dispatcher evaluation task (N2): logs the fault via the
|
||||
/// existing error path (which also increments the health counter), then reuses the
|
||||
/// false-result path — clearing in-flight, applying the false edge, and draining any
|
||||
/// pending evaluation — so a transient scheduler fault cannot permanently park the trigger.
|
||||
/// </summary>
|
||||
private void HandleExpressionEvalFailed(ExpressionEvalFailed msg)
|
||||
{
|
||||
LogExpressionError(msg.Cause);
|
||||
HandleExpressionEvalResult(new ExpressionEvalResult(false));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a WhileTrue trigger's condition-state transition: on the
|
||||
/// false→true edge, fire once and start the re-fire timer; on the
|
||||
@@ -621,6 +638,15 @@ public class ScriptActor : ReceiveActor, IWithTimers
|
||||
/// the actor thread.
|
||||
/// </summary>
|
||||
private sealed record ExpressionEvalResult(bool Result);
|
||||
|
||||
/// <summary>
|
||||
/// Piped back to self when the off-dispatcher evaluation TASK itself faults
|
||||
/// (e.g. ObjectDisposedException from a disposed ScriptExecutionScheduler
|
||||
/// during shutdown) — the inner body's catch never sees that. Without this
|
||||
/// mapping the actor receives an unhandled Status.Failure and _evalInFlight
|
||||
/// stays true forever, permanently parking the expression trigger (N2).
|
||||
/// </summary>
|
||||
internal sealed record ExpressionEvalFailed(Exception Cause);
|
||||
}
|
||||
|
||||
// ── Trigger config types ──
|
||||
|
||||
Reference in New Issue
Block a user