feat(gateway): configurable worker write-completion wait (MxGateway:Worker:WriteCompletionWaitMilliseconds)
This commit is contained in:
@@ -225,6 +225,10 @@ public sealed class GatewayOptionsValidator : OptionsValidatorBase<GatewayOption
|
|||||||
options.PipeConnectAttemptTimeoutMilliseconds,
|
options.PipeConnectAttemptTimeoutMilliseconds,
|
||||||
"MxGateway:Worker:PipeConnectAttemptTimeoutMilliseconds must be greater than zero.",
|
"MxGateway:Worker:PipeConnectAttemptTimeoutMilliseconds must be greater than zero.",
|
||||||
builder);
|
builder);
|
||||||
|
if (options.WriteCompletionWaitMilliseconds < 0)
|
||||||
|
{
|
||||||
|
builder.Add("MxGateway:Worker:WriteCompletionWaitMilliseconds must be greater than or equal to zero.");
|
||||||
|
}
|
||||||
AddIfNotPositive(
|
AddIfNotPositive(
|
||||||
options.ShutdownTimeoutSeconds,
|
options.ShutdownTimeoutSeconds,
|
||||||
"MxGateway:Worker:ShutdownTimeoutSeconds must be greater than zero.",
|
"MxGateway:Worker:ShutdownTimeoutSeconds must be greater than zero.",
|
||||||
|
|||||||
@@ -24,6 +24,15 @@ public sealed class WorkerOptions
|
|||||||
/// <summary>The timeout in milliseconds for connecting to the worker pipe.</summary>
|
/// <summary>The timeout in milliseconds for connecting to the worker pipe.</summary>
|
||||||
public int PipeConnectAttemptTimeoutMilliseconds { get; init; } = 2000;
|
public int PipeConnectAttemptTimeoutMilliseconds { get; init; } = 2000;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bounded wait, in milliseconds, the worker holds a WriteSecured/WriteSecured2
|
||||||
|
/// reply for the matching MXAccess OnWriteComplete callback so the reply's
|
||||||
|
/// statuses carry the real commit outcome. 0 disables the wait. Deployments
|
||||||
|
/// raising this above consumer write-timeout budgets (e.g. OtOpcUa's 2 s Tier A
|
||||||
|
/// write resilience timeout) must raise those in step.
|
||||||
|
/// </summary>
|
||||||
|
public int WriteCompletionWaitMilliseconds { get; init; } = 1500;
|
||||||
|
|
||||||
/// <summary>The maximum time in seconds for graceful shutdown.</summary>
|
/// <summary>The maximum time in seconds for graceful shutdown.</summary>
|
||||||
public int ShutdownTimeoutSeconds { get; init; } = 10;
|
public int ShutdownTimeoutSeconds { get; init; } = 10;
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ public sealed class WorkerProcessLauncher : IWorkerProcessLauncher
|
|||||||
public const string WorkerPipeConnectAttemptTimeoutEnvironmentVariableName =
|
public const string WorkerPipeConnectAttemptTimeoutEnvironmentVariableName =
|
||||||
"MXGATEWAY_WORKER_PIPE_CONNECT_ATTEMPT_TIMEOUT_MS";
|
"MXGATEWAY_WORKER_PIPE_CONNECT_ATTEMPT_TIMEOUT_MS";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Conveys MxGateway:Worker:WriteCompletionWaitMilliseconds to the worker:
|
||||||
|
/// the bounded wait for the OnWriteComplete callback on
|
||||||
|
/// WriteSecured/WriteSecured2 replies. 0 disables the wait.
|
||||||
|
/// </summary>
|
||||||
|
public const string WorkerWriteCompletionWaitEnvironmentVariableName =
|
||||||
|
"MXGATEWAY_WORKER_WRITE_COMPLETION_WAIT_MS";
|
||||||
|
|
||||||
private readonly IWorkerProcessFactory _processFactory;
|
private readonly IWorkerProcessFactory _processFactory;
|
||||||
private readonly IWorkerStartupProbe _startupProbe;
|
private readonly IWorkerStartupProbe _startupProbe;
|
||||||
private readonly GatewayMetrics _metrics;
|
private readonly GatewayMetrics _metrics;
|
||||||
@@ -175,6 +183,8 @@ public sealed class WorkerProcessLauncher : IWorkerProcessLauncher
|
|||||||
startInfo.Environment[WorkerNonceEnvironmentVariableName] = request.Nonce;
|
startInfo.Environment[WorkerNonceEnvironmentVariableName] = request.Nonce;
|
||||||
startInfo.Environment[WorkerPipeConnectAttemptTimeoutEnvironmentVariableName] =
|
startInfo.Environment[WorkerPipeConnectAttemptTimeoutEnvironmentVariableName] =
|
||||||
_workerOptions.PipeConnectAttemptTimeoutMilliseconds.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
_workerOptions.PipeConnectAttemptTimeoutMilliseconds.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||||||
|
startInfo.Environment[WorkerWriteCompletionWaitEnvironmentVariableName] =
|
||||||
|
_workerOptions.WriteCompletionWaitMilliseconds.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
commandLine = new WorkerProcessCommandLine(executablePath, arguments);
|
commandLine = new WorkerProcessCommandLine(executablePath, arguments);
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public sealed class GatewayOptionsTests
|
|||||||
Assert.Equal(3, options.Worker.StartupProbeRetryAttempts);
|
Assert.Equal(3, options.Worker.StartupProbeRetryAttempts);
|
||||||
Assert.Equal(250, options.Worker.StartupProbeRetryDelayMilliseconds);
|
Assert.Equal(250, options.Worker.StartupProbeRetryDelayMilliseconds);
|
||||||
Assert.Equal(2000, options.Worker.PipeConnectAttemptTimeoutMilliseconds);
|
Assert.Equal(2000, options.Worker.PipeConnectAttemptTimeoutMilliseconds);
|
||||||
|
Assert.Equal(1500, options.Worker.WriteCompletionWaitMilliseconds);
|
||||||
Assert.Equal(10, options.Worker.ShutdownTimeoutSeconds);
|
Assert.Equal(10, options.Worker.ShutdownTimeoutSeconds);
|
||||||
Assert.Equal(5, options.Worker.HeartbeatIntervalSeconds);
|
Assert.Equal(5, options.Worker.HeartbeatIntervalSeconds);
|
||||||
Assert.Equal(15, options.Worker.HeartbeatGraceSeconds);
|
Assert.Equal(15, options.Worker.HeartbeatGraceSeconds);
|
||||||
@@ -106,6 +107,7 @@ public sealed class GatewayOptionsTests
|
|||||||
[InlineData("MxGateway:Worker:ExecutablePath", "worker.dll", "MxGateway:Worker:ExecutablePath must point to a .exe file.")]
|
[InlineData("MxGateway:Worker:ExecutablePath", "worker.dll", "MxGateway:Worker:ExecutablePath must point to a .exe file.")]
|
||||||
[InlineData("MxGateway:Worker:StartupProbeRetryAttempts", "0", "MxGateway:Worker:StartupProbeRetryAttempts must be greater than zero.")]
|
[InlineData("MxGateway:Worker:StartupProbeRetryAttempts", "0", "MxGateway:Worker:StartupProbeRetryAttempts must be greater than zero.")]
|
||||||
[InlineData("MxGateway:Worker:PipeConnectAttemptTimeoutMilliseconds", "0", "MxGateway:Worker:PipeConnectAttemptTimeoutMilliseconds must be greater than zero.")]
|
[InlineData("MxGateway:Worker:PipeConnectAttemptTimeoutMilliseconds", "0", "MxGateway:Worker:PipeConnectAttemptTimeoutMilliseconds must be greater than zero.")]
|
||||||
|
[InlineData("MxGateway:Worker:WriteCompletionWaitMilliseconds", "-1", "MxGateway:Worker:WriteCompletionWaitMilliseconds must be greater than or equal to zero.")]
|
||||||
[InlineData("MxGateway:Sessions:DefaultLeaseSeconds", "0", "MxGateway:Sessions:DefaultLeaseSeconds must be greater than zero.")]
|
[InlineData("MxGateway:Sessions:DefaultLeaseSeconds", "0", "MxGateway:Sessions:DefaultLeaseSeconds must be greater than zero.")]
|
||||||
[InlineData("MxGateway:Sessions:LeaseSweepIntervalSeconds", "0", "MxGateway:Sessions:LeaseSweepIntervalSeconds must be greater than zero.")]
|
[InlineData("MxGateway:Sessions:LeaseSweepIntervalSeconds", "0", "MxGateway:Sessions:LeaseSweepIntervalSeconds must be greater than zero.")]
|
||||||
[InlineData("MxGateway:Sessions:DetachGraceSeconds", "-1", "MxGateway:Sessions:DetachGraceSeconds must be zero or greater (0 disables detach-grace retention).")]
|
[InlineData("MxGateway:Sessions:DetachGraceSeconds", "-1", "MxGateway:Sessions:DetachGraceSeconds must be zero or greater (0 disables detach-grace retention).")]
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ public sealed class WorkerProcessLauncherTests
|
|||||||
"2000",
|
"2000",
|
||||||
processFactory.LastStartInfo.Environment[
|
processFactory.LastStartInfo.Environment[
|
||||||
WorkerProcessLauncher.WorkerPipeConnectAttemptTimeoutEnvironmentVariableName]);
|
WorkerProcessLauncher.WorkerPipeConnectAttemptTimeoutEnvironmentVariableName]);
|
||||||
|
Assert.Equal(
|
||||||
|
"1500",
|
||||||
|
processFactory.LastStartInfo.Environment[
|
||||||
|
WorkerProcessLauncher.WorkerWriteCompletionWaitEnvironmentVariableName]);
|
||||||
Assert.DoesNotContain(Nonce, handle.CommandLine.ToString(), StringComparison.Ordinal);
|
Assert.DoesNotContain(Nonce, handle.CommandLine.ToString(), StringComparison.Ordinal);
|
||||||
Assert.DoesNotContain(Nonce, string.Join(" ", handle.CommandLine.Arguments), StringComparison.Ordinal);
|
Assert.DoesNotContain(Nonce, string.Join(" ", handle.CommandLine.Arguments), StringComparison.Ordinal);
|
||||||
Assert.False(pipeReservation.DisposeCalled);
|
Assert.False(pipeReservation.DisposeCalled);
|
||||||
|
|||||||
Reference in New Issue
Block a user