Add SiteReplicationActor (runs on every site node) to replicate deployed configs and store-and-forward buffer operations to the standby peer via cluster member discovery and fire-and-forget Tell. Wire ReplicationService handler and pass replication actor to DeploymentManagerActor singleton. Fix 5 pre-existing ConfigurationDatabase test failures: RowVersion NOT NULL on SQLite, stale migration name assertion, and seed data count mismatch.
63 lines
1.9 KiB
C#
63 lines
1.9 KiB
C#
using ScadaLink.Commons.Types;
|
|
|
|
namespace ScadaLink.Commons.Interfaces.Services;
|
|
|
|
/// <summary>
|
|
/// Interface for invoking external system HTTP APIs.
|
|
/// Implemented by ExternalSystemGateway, consumed by ScriptRuntimeContext.
|
|
/// </summary>
|
|
public interface IExternalSystemClient
|
|
{
|
|
/// <summary>
|
|
/// Synchronous call to an external system. All failures returned to caller.
|
|
/// </summary>
|
|
Task<ExternalCallResult> CallAsync(
|
|
string systemName,
|
|
string methodName,
|
|
IReadOnlyDictionary<string, object?>? parameters = null,
|
|
CancellationToken cancellationToken = default);
|
|
|
|
/// <summary>
|
|
/// Attempt immediate delivery; on transient failure, hand to S&F engine.
|
|
/// Permanent failures returned to caller.
|
|
/// </summary>
|
|
Task<ExternalCallResult> CachedCallAsync(
|
|
string systemName,
|
|
string methodName,
|
|
IReadOnlyDictionary<string, object?>? parameters = null,
|
|
string? originInstanceName = null,
|
|
CancellationToken cancellationToken = default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Result of an external system call.
|
|
/// </summary>
|
|
public record ExternalCallResult(
|
|
bool Success,
|
|
string? ResponseJson,
|
|
string? ErrorMessage,
|
|
bool WasBuffered = false)
|
|
{
|
|
private dynamic? _response;
|
|
private bool _responseParsed;
|
|
|
|
/// <summary>
|
|
/// Parsed response as a dynamic object. Returns null if ResponseJson is null or empty.
|
|
/// Access properties directly: result.Response.result, result.Response.items[0].name, etc.
|
|
/// </summary>
|
|
public dynamic? Response
|
|
{
|
|
get
|
|
{
|
|
if (!_responseParsed)
|
|
{
|
|
_response = string.IsNullOrEmpty(ResponseJson)
|
|
? null
|
|
: new DynamicJsonElement(System.Text.Json.JsonDocument.Parse(ResponseJson).RootElement);
|
|
_responseParsed = true;
|
|
}
|
|
return _response;
|
|
}
|
|
}
|
|
}
|