fix(site-runtime): site-side compile failure now rejects the deployment per spec (S3) — synchronous validation gate before actor creation
Validation runs on the actor thread (not off-thread as the plan sketched): piping the verdict back to self reorders concurrent deploys relative to each other and to delete/disable, breaking the redeploy-supersede FIFO ordering (SR020/SR029). A deploy is an infrequent admin command, so a brief synchronous Roslyn compile is acceptable.
This commit is contained in:
@@ -35,6 +35,10 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
|
||||
{
|
||||
private readonly SiteStorageService _storage;
|
||||
private readonly ScriptCompilationService _compilationService;
|
||||
// Pure, off-thread deploy-time compile gate. A site-side compile failure
|
||||
// must reject the deployment (spec: no partial state applied), so every
|
||||
// DeployInstanceCommand is validated before any actor/persistence work.
|
||||
private readonly DeployCompileValidator _deployCompileValidator;
|
||||
private readonly SharedScriptLibrary _sharedScriptLibrary;
|
||||
private readonly SiteStreamManager? _streamManager;
|
||||
private readonly SiteRuntimeOptions _options;
|
||||
@@ -125,6 +129,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
|
||||
{
|
||||
_storage = storage;
|
||||
_compilationService = compilationService;
|
||||
_deployCompileValidator = new DeployCompileValidator(compilationService);
|
||||
_sharedScriptLibrary = sharedScriptLibrary;
|
||||
_streamManager = streamManager;
|
||||
_options = options;
|
||||
@@ -387,6 +392,41 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
|
||||
/// apply still replies to the right actor.
|
||||
/// </param>
|
||||
private void HandleDeploy(DeployInstanceCommand command, IActorRef replyTo)
|
||||
{
|
||||
// Site-side compile gate (S3): a compile failure must reject the
|
||||
// deployment with NO partial state applied (no Instance Actor, no
|
||||
// persisted config) — the design spec's contract. Validation runs
|
||||
// synchronously on the actor thread: it is a pure prefix step of the
|
||||
// deploy handler, so the existing redeploy-supersede / delete-during-
|
||||
// redeploy ordering (which depends on strict mailbox FIFO) is preserved
|
||||
// exactly. It is NOT run off-thread — piping the verdict back to self
|
||||
// reorders concurrent deploys relative to each other and to
|
||||
// delete/disable commands, breaking that ordering. A deploy is an
|
||||
// infrequent admin command, so briefly holding the singleton for a pure
|
||||
// Roslyn compile is acceptable; the central deployer already Asks and
|
||||
// waits for the DeploymentStatusResponse.
|
||||
var errors = _deployCompileValidator.Validate(command.FlattenedConfigurationJson);
|
||||
if (errors.Count > 0)
|
||||
{
|
||||
var instanceName = command.InstanceUniqueName;
|
||||
var joined = string.Join(" | ", errors);
|
||||
LogDeploymentEvent("Error", instanceName,
|
||||
$"Instance {instanceName} deploy rejected — site compile validation failed (deploymentId={command.DeploymentId})",
|
||||
joined);
|
||||
replyTo.Tell(new DeploymentStatusResponse(
|
||||
command.DeploymentId, instanceName, DeploymentStatus.Failed,
|
||||
"Script compilation failed on site: " + joined, DateTimeOffset.UtcNow));
|
||||
return;
|
||||
}
|
||||
|
||||
ProceedWithDeploy(command, replyTo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Core deploy application (redeploy-supersede + fresh apply), reached only
|
||||
/// after the synchronous compile gate in <see cref="HandleDeploy"/> passes.
|
||||
/// </summary>
|
||||
private void ProceedWithDeploy(DeployInstanceCommand command, IActorRef replyTo)
|
||||
{
|
||||
var instanceName = command.InstanceUniqueName;
|
||||
_logger.LogInformation(
|
||||
|
||||
@@ -1336,7 +1336,9 @@ public class InstanceActor : ReceiveActor
|
||||
/// Creates child Script Actors and Alarm Actors from the flattened configuration.
|
||||
/// Script Actors spawned per script definition.
|
||||
/// Alarm Actors spawned per alarm definition, as peers to Script Actors.
|
||||
/// Compilation errors reject entire instance deployment (logged but actor still starts).
|
||||
/// Compile failures are rejected at deploy time by the Deployment Manager's
|
||||
/// validation gate; a failure reaching this point (startup load of a legacy
|
||||
/// config) is logged and the offending script/alarm skipped.
|
||||
///
|
||||
/// Each child is seeded from a private point-in-time snapshot
|
||||
/// of <c>_attributes</c>, NOT the live dictionary. The snapshot is taken here on
|
||||
|
||||
Reference in New Issue
Block a user