042f5e3d82
- EffectiveSessionConfiguration: add DetachGraceSeconds field; GatewayConfigurationProvider forwards value.Sessions.DetachGraceSeconds (blocker fix). - GatewaySession.InvokeAsync and ReadEventsAsync: switch TouchClientActivity calls from DateTimeOffset.UtcNow to _eventStreaming.TimeProvider.GetUtcNow() so Task 12 fake-clock control works end-to-end (split-clock fix). - TOCTOU fix: add TryBeginCloseIfExpired(now, out alreadyClosing) to GatewaySession that re-checks IsLeaseExpiredCore/IsDetachGraceExpiredCore AND _activeEventSubscriberCount==0 under _syncRoot before transitioning to Closing; CloseExpiredLeasesAsync calls it before CloseSessionCoreAsync so a reattach that wins the race leaves the session Ready/usable. - Minors: lease-expiry-takes-precedence comment in CloseExpiredLeasesAsync; TOCTOU comment block; sweep-cycle latency note added to SessionOptions.DetachGraceSeconds XML doc and to GatewayConfiguration.md DetachGraceSeconds row. - New tests: TryBeginCloseIfExpired_ReattachedSubscriberWinsRace_DeclinesClose (GatewaySession), CloseExpiredLeasesAsync_DoesNotCloseSessionThatReattachedBeforeSweepCloses (SessionManager), plus IsLeaseExpiredCore/IsDetachGraceExpiredCore private helpers used by the guard.
70 lines
3.9 KiB
C#
70 lines
3.9 KiB
C#
using Microsoft.Extensions.Options;
|
|
|
|
namespace ZB.MOM.WW.MxGateway.Server.Configuration;
|
|
|
|
/// <summary>Provides the effective gateway configuration with sensitive values redacted.</summary>
|
|
public sealed class GatewayConfigurationProvider(IOptions<GatewayOptions> options) : IGatewayConfigurationProvider
|
|
{
|
|
/// <summary>Marker string for redacted sensitive configuration values.</summary>
|
|
public const string RedactedValue = "[redacted]";
|
|
|
|
/// <inheritdoc />
|
|
public EffectiveGatewayConfiguration GetEffectiveConfiguration()
|
|
{
|
|
GatewayOptions value = options.Value;
|
|
|
|
return new EffectiveGatewayConfiguration(
|
|
Authentication: new EffectiveAuthenticationConfiguration(
|
|
Mode: value.Authentication.Mode.ToString(),
|
|
SqlitePath: value.Authentication.SqlitePath,
|
|
PepperSecretName: RedactedValue,
|
|
RunMigrationsOnStartup: value.Authentication.RunMigrationsOnStartup),
|
|
Ldap: new EffectiveLdapConfiguration(
|
|
Enabled: value.Ldap.Enabled,
|
|
Server: value.Ldap.Server,
|
|
Port: value.Ldap.Port,
|
|
Transport: value.Ldap.Transport.ToString(),
|
|
AllowInsecure: value.Ldap.AllowInsecure,
|
|
SearchBase: value.Ldap.SearchBase,
|
|
ServiceAccountDn: value.Ldap.ServiceAccountDn,
|
|
ServiceAccountPassword: RedactedValue,
|
|
UserNameAttribute: value.Ldap.UserNameAttribute,
|
|
DisplayNameAttribute: value.Ldap.DisplayNameAttribute,
|
|
GroupAttribute: value.Ldap.GroupAttribute),
|
|
Worker: new EffectiveWorkerConfiguration(
|
|
ExecutablePath: value.Worker.ExecutablePath,
|
|
WorkingDirectory: value.Worker.WorkingDirectory,
|
|
RequiredArchitecture: value.Worker.RequiredArchitecture.ToString(),
|
|
StartupTimeoutSeconds: value.Worker.StartupTimeoutSeconds,
|
|
ShutdownTimeoutSeconds: value.Worker.ShutdownTimeoutSeconds,
|
|
HeartbeatIntervalSeconds: value.Worker.HeartbeatIntervalSeconds,
|
|
HeartbeatGraceSeconds: value.Worker.HeartbeatGraceSeconds,
|
|
MaxMessageBytes: value.Worker.MaxMessageBytes),
|
|
Sessions: new EffectiveSessionConfiguration(
|
|
DefaultCommandTimeoutSeconds: value.Sessions.DefaultCommandTimeoutSeconds,
|
|
MaxSessions: value.Sessions.MaxSessions,
|
|
MaxPendingCommandsPerSession: value.Sessions.MaxPendingCommandsPerSession,
|
|
DefaultLeaseSeconds: value.Sessions.DefaultLeaseSeconds,
|
|
LeaseSweepIntervalSeconds: value.Sessions.LeaseSweepIntervalSeconds,
|
|
DetachGraceSeconds: value.Sessions.DetachGraceSeconds,
|
|
AllowMultipleEventSubscribers: value.Sessions.AllowMultipleEventSubscribers,
|
|
MaxEventSubscribersPerSession: value.Sessions.MaxEventSubscribersPerSession),
|
|
Events: new EffectiveEventConfiguration(
|
|
QueueCapacity: value.Events.QueueCapacity,
|
|
BackpressurePolicy: value.Events.BackpressurePolicy.ToString(),
|
|
ReplayBufferCapacity: value.Events.ReplayBufferCapacity,
|
|
ReplayRetentionSeconds: value.Events.ReplayRetentionSeconds),
|
|
Dashboard: new EffectiveDashboardConfiguration(
|
|
Enabled: value.Dashboard.Enabled,
|
|
AllowAnonymousLocalhost: value.Dashboard.AllowAnonymousLocalhost,
|
|
SnapshotIntervalMilliseconds: value.Dashboard.SnapshotIntervalMilliseconds,
|
|
RecentFaultLimit: value.Dashboard.RecentFaultLimit,
|
|
RecentSessionLimit: value.Dashboard.RecentSessionLimit,
|
|
ShowTagValues: value.Dashboard.ShowTagValues,
|
|
GroupToRole: value.Dashboard.GroupToRole),
|
|
Protocol: new EffectiveProtocolConfiguration(
|
|
value.Protocol.WorkerProtocolVersion,
|
|
value.Protocol.MaxGrpcMessageBytes));
|
|
}
|
|
}
|