feat(dcl): extend CreateConnectionCommand with backup config and failover retry count
Update CreateConnectionCommand to carry PrimaryConnectionDetails, BackupConnectionDetails, and FailoverRetryCount. Update all callers: DataConnectionManagerActor, DataConnectionActor, DeploymentManagerActor, FlatteningService, and ConnectionConfig. The actor stores both configs but continues using primary only — failover logic comes in Task 3.
This commit is contained in:
@@ -7,4 +7,6 @@ namespace ScadaLink.Commons.Messages.DataConnection;
|
|||||||
public record CreateConnectionCommand(
|
public record CreateConnectionCommand(
|
||||||
string ConnectionName,
|
string ConnectionName,
|
||||||
string ProtocolType,
|
string ProtocolType,
|
||||||
IDictionary<string, string> ConnectionDetails);
|
IDictionary<string, string> PrimaryConnectionDetails,
|
||||||
|
IDictionary<string, string>? BackupConnectionDetails = null,
|
||||||
|
int FailoverRetryCount = 3);
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ public sealed record ConnectionConfig
|
|||||||
{
|
{
|
||||||
public string Protocol { get; init; } = string.Empty;
|
public string Protocol { get; init; } = string.Empty;
|
||||||
public string? ConfigurationJson { get; init; }
|
public string? ConfigurationJson { get; init; }
|
||||||
|
public string? BackupConfigurationJson { get; init; }
|
||||||
|
public int FailoverRetryCount { get; init; } = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ public class DataConnectionActor : UntypedActor, IWithStash, IWithTimers
|
|||||||
private int _resolvedTags;
|
private int _resolvedTags;
|
||||||
|
|
||||||
private readonly IDictionary<string, string> _connectionDetails;
|
private readonly IDictionary<string, string> _connectionDetails;
|
||||||
|
private readonly IDictionary<string, string> _primaryConfig;
|
||||||
|
private readonly IDictionary<string, string>? _backupConfig;
|
||||||
|
private readonly int _failoverRetryCount;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Captured Self reference for use from non-actor threads (event handlers, callbacks).
|
/// Captured Self reference for use from non-actor threads (event handlers, callbacks).
|
||||||
@@ -73,13 +76,18 @@ public class DataConnectionActor : UntypedActor, IWithStash, IWithTimers
|
|||||||
IDataConnection adapter,
|
IDataConnection adapter,
|
||||||
DataConnectionOptions options,
|
DataConnectionOptions options,
|
||||||
ISiteHealthCollector healthCollector,
|
ISiteHealthCollector healthCollector,
|
||||||
IDictionary<string, string>? connectionDetails = null)
|
IDictionary<string, string>? primaryConfig = null,
|
||||||
|
IDictionary<string, string>? backupConfig = null,
|
||||||
|
int failoverRetryCount = 3)
|
||||||
{
|
{
|
||||||
_connectionName = connectionName;
|
_connectionName = connectionName;
|
||||||
_adapter = adapter;
|
_adapter = adapter;
|
||||||
_options = options;
|
_options = options;
|
||||||
_healthCollector = healthCollector;
|
_healthCollector = healthCollector;
|
||||||
_connectionDetails = connectionDetails ?? new Dictionary<string, string>();
|
_primaryConfig = primaryConfig ?? new Dictionary<string, string>();
|
||||||
|
_backupConfig = backupConfig;
|
||||||
|
_failoverRetryCount = failoverRetryCount;
|
||||||
|
_connectionDetails = _primaryConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PreStart()
|
protected override void PreStart()
|
||||||
|
|||||||
@@ -45,10 +45,13 @@ public class DataConnectionManagerActor : ReceiveActor
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WP-34: Factory creates the correct adapter based on protocol type
|
// WP-34: Factory creates the correct adapter based on protocol type
|
||||||
var adapter = _factory.Create(command.ProtocolType, command.ConnectionDetails);
|
var adapter = _factory.Create(command.ProtocolType, command.PrimaryConnectionDetails);
|
||||||
|
|
||||||
var props = Props.Create(() => new DataConnectionActor(
|
var props = Props.Create(() => new DataConnectionActor(
|
||||||
command.ConnectionName, adapter, _options, _healthCollector, command.ConnectionDetails));
|
command.ConnectionName, adapter, _options, _healthCollector,
|
||||||
|
command.PrimaryConnectionDetails,
|
||||||
|
command.BackupConnectionDetails,
|
||||||
|
command.FailoverRetryCount));
|
||||||
|
|
||||||
// Sanitize name for Akka actor path (replace spaces and invalid chars)
|
// Sanitize name for Akka actor path (replace spaces and invalid chars)
|
||||||
var actorName = new string(command.ConnectionName
|
var actorName = new string(command.ConnectionName
|
||||||
|
|||||||
@@ -422,7 +422,7 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
|
|||||||
if (_createdConnections.Contains(name))
|
if (_createdConnections.Contains(name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var connectionDetails = new Dictionary<string, string>();
|
var primaryDetails = new Dictionary<string, string>();
|
||||||
if (!string.IsNullOrEmpty(connConfig.ConfigurationJson))
|
if (!string.IsNullOrEmpty(connConfig.ConfigurationJson))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -431,14 +431,29 @@ public class DeploymentManagerActor : ReceiveActor, IWithTimers
|
|||||||
using var doc = System.Text.Json.JsonDocument.Parse(connConfig.ConfigurationJson);
|
using var doc = System.Text.Json.JsonDocument.Parse(connConfig.ConfigurationJson);
|
||||||
foreach (var prop in doc.RootElement.EnumerateObject())
|
foreach (var prop in doc.RootElement.EnumerateObject())
|
||||||
{
|
{
|
||||||
connectionDetails[prop.Name] = prop.Value.ToString();
|
primaryDetails[prop.Name] = prop.Value.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { /* Ignore parse errors */ }
|
catch { /* Ignore parse errors */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dictionary<string, string>? backupDetails = null;
|
||||||
|
if (!string.IsNullOrEmpty(connConfig.BackupConfigurationJson))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
backupDetails = new Dictionary<string, string>();
|
||||||
|
using var doc = System.Text.Json.JsonDocument.Parse(connConfig.BackupConfigurationJson);
|
||||||
|
foreach (var prop in doc.RootElement.EnumerateObject())
|
||||||
|
{
|
||||||
|
backupDetails[prop.Name] = prop.Value.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { backupDetails = null; /* Ignore parse errors */ }
|
||||||
|
}
|
||||||
|
|
||||||
_dclManager.Tell(new Commons.Messages.DataConnection.CreateConnectionCommand(
|
_dclManager.Tell(new Commons.Messages.DataConnection.CreateConnectionCommand(
|
||||||
name, connConfig.Protocol, connectionDetails));
|
name, connConfig.Protocol, primaryDetails, backupDetails, connConfig.FailoverRetryCount));
|
||||||
|
|
||||||
_createdConnections.Add(name);
|
_createdConnections.Add(name);
|
||||||
_logger.LogInformation(
|
_logger.LogInformation(
|
||||||
|
|||||||
@@ -90,7 +90,9 @@ public class FlatteningService
|
|||||||
connections[attr.BoundDataConnectionName] = new ConnectionConfig
|
connections[attr.BoundDataConnectionName] = new ConnectionConfig
|
||||||
{
|
{
|
||||||
Protocol = conn.Protocol,
|
Protocol = conn.Protocol,
|
||||||
ConfigurationJson = conn.PrimaryConfiguration
|
ConfigurationJson = conn.PrimaryConfiguration,
|
||||||
|
BackupConfigurationJson = conn.BackupConfiguration,
|
||||||
|
FailoverRetryCount = conn.FailoverRetryCount
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public class DataConnectionManagerActorTests : TestKit
|
|||||||
new DataConnectionManagerActor(_mockFactory, _options, _mockHealthCollector)));
|
new DataConnectionManagerActor(_mockFactory, _options, _mockHealthCollector)));
|
||||||
|
|
||||||
manager.Tell(new CreateConnectionCommand(
|
manager.Tell(new CreateConnectionCommand(
|
||||||
"conn1", "OpcUa", new Dictionary<string, string>()));
|
"conn1", "OpcUa", new Dictionary<string, string>(), null, 3));
|
||||||
|
|
||||||
// Factory should have been called
|
// Factory should have been called
|
||||||
AwaitCondition(() =>
|
AwaitCondition(() =>
|
||||||
|
|||||||
Reference in New Issue
Block a user