fix(dcl): ASCII-only connection actor names, guarded ActorOf, and gate rejection of colliding connection names (review 2026-10-21 lane A M2)
ConnectionActorNames.Sanitize (shared by the DCL manager and the site deploy gate) keeps ASCII letters/digits and -_.*+:@&=,!~';() only. The manager fails a connection whose sanitised name is invalid or already used (Error + site event) instead of restarting; DeployCompileValidator rejects a config whose connection names collide after sanitising.
This commit is contained in:
@@ -92,11 +92,37 @@ public class DataConnectionManagerActor : ReceiveActor
|
||||
command.FailoverRetryCount,
|
||||
_siteEventLogger));
|
||||
|
||||
// Sanitize name for Akka actor path (replace spaces and invalid chars)
|
||||
var actorName = new string(command.ConnectionName
|
||||
.Select(c => char.IsLetterOrDigit(c) || "-_.*$+:@&=,!~';()".Contains(c) ? c : '-')
|
||||
.ToArray());
|
||||
var actorRef = Context.ActorOf(props, actorName);
|
||||
// Sanitize name for Akka actor path — ASCII only, never a leading '$' (see
|
||||
// ConnectionActorNames). Two connection names can still sanitise to the same actor name
|
||||
// ("PLC A" / "PLC-A"), and ActorOf throws synchronously on that (or on any name Akka
|
||||
// refuses): that must fail THIS connection only, never escape to the supervisor and
|
||||
// restart the whole manager with every live connection (review 2026-10-21, lane A M2).
|
||||
var actorName = ConnectionActorNames.Sanitize(command.ConnectionName);
|
||||
IActorRef actorRef;
|
||||
try
|
||||
{
|
||||
if (!Context.Child(actorName).IsNobody())
|
||||
throw new InvalidActorNameException(
|
||||
$"actor name [{actorName}] is already used by another connection");
|
||||
actorRef = Context.ActorOf(props, actorName);
|
||||
}
|
||||
catch (InvalidActorNameException ex)
|
||||
{
|
||||
_log.Error(
|
||||
"Connection {0} not created: its actor name '{1}' is invalid or already used by another " +
|
||||
"connection ({2}). Rename the connection so its name differs in more than spaces/symbols.",
|
||||
command.ConnectionName, actorName, ex.Message);
|
||||
if (_siteEventLogger != null)
|
||||
{
|
||||
_ = _siteEventLogger.LogEventAsync(
|
||||
"connection", "Error", null, command.ConnectionName,
|
||||
$"Connection not created — runtime actor name '{actorName}' is invalid or already in use",
|
||||
ex.Message);
|
||||
}
|
||||
adapter.DisposeAsync().AsTask().ContinueWith(_ => { });
|
||||
return;
|
||||
}
|
||||
|
||||
_connectionActors[command.ConnectionName] = actorRef;
|
||||
|
||||
_log.Info("Created DataConnectionActor for {0} (protocol={1})",
|
||||
|
||||
Reference in New Issue
Block a user