fix(r2-04): Galaxy fail-closed write when AdviseSupervisory fails - Bad status feeds #5 node revert (06/S-1)
This commit is contained in:
@@ -178,8 +178,16 @@ public sealed class GatewayGalaxyDataWriter : IGalaxyDataWriter
|
||||
// A raw Write runs with NO user login (WriteUserId is typically 0), so MXAccess
|
||||
// only COMMITS the value when the item is advised in SUPERVISORY mode. Without it
|
||||
// the gateway's Write call doesn't throw (reply looks OK) but the value never
|
||||
// reaches the galaxy. AdviseSupervisory once per handle, then Write.
|
||||
await EnsureSupervisoryAdvisedAsync(ops, itemHandle, ct).ConfigureAwait(false);
|
||||
// reaches the galaxy — a knowingly-lost write. FAIL-CLOSED (archreview 06/S-1): when
|
||||
// AdviseSupervisory fails we do NOT issue the raw Write; we return Bad so the
|
||||
// #5 write-outcome self-correction reverts the phantom-Good node instead of leaving it.
|
||||
// The real fix is a gateway-side WriteComplete correlation (mxaccessgw backlog) so the
|
||||
// unary reply's Statuses carry the actual COM commit outcome; until then advise-status +
|
||||
// the galaxy.writes.* meters are the honest signal.
|
||||
if (!await EnsureSupervisoryAdvisedAsync(ops, itemHandle, ct).ConfigureAwait(false))
|
||||
{
|
||||
return new WriteResult(StatusCodeMap.BadCommunicationError);
|
||||
}
|
||||
reply = await ops.WriteRawAsync(itemHandle, mxValue, _writeUserId, ct)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
@@ -226,10 +234,16 @@ public sealed class GatewayGalaxyDataWriter : IGalaxyDataWriter
|
||||
/// session reconnect via <see cref="InvalidateHandleCaches"/>, so a fresh session always
|
||||
/// re-advises — the supervisory state never outlives the handle it was taken against.
|
||||
/// </summary>
|
||||
private async Task EnsureSupervisoryAdvisedAsync(
|
||||
/// <summary>Ensure the item is supervisory-advised so a no-login raw Write can commit. Returns
|
||||
/// <c>true</c> when the item is advised (already-advised this session, or the advise round-trip
|
||||
/// succeeded), <c>false</c> when the advise failed — the caller then FAILS THE WRITE CLOSED
|
||||
/// (archreview 06/S-1) rather than issuing a raw Write that cannot commit.</summary>
|
||||
/// <returns><c>true</c> when advised; <c>false</c> when the advise failed (caller must not write).</returns>
|
||||
private async Task<bool> EnsureSupervisoryAdvisedAsync(
|
||||
IMxWriteOps ops, int itemHandle, CancellationToken ct)
|
||||
{
|
||||
if (!_supervisedHandles.TryAdd(itemHandle, 0)) return;
|
||||
// Already advised this session (a prior successful advise on this handle) — nothing to do.
|
||||
if (!_supervisedHandles.TryAdd(itemHandle, 0)) return true;
|
||||
|
||||
var request = new MxCommandRequest
|
||||
{
|
||||
@@ -249,13 +263,16 @@ public sealed class GatewayGalaxyDataWriter : IGalaxyDataWriter
|
||||
var reply = await ops.InvokeAsync(request, ct).ConfigureAwait(false);
|
||||
if (reply.ProtocolStatus is { } proto && proto.Code != ProtocolStatusCode.Ok)
|
||||
{
|
||||
// Supervisory advise failed — forget it so the next write retries, and let the
|
||||
// write proceed (it surfaces its own status via TranslateReply).
|
||||
// Supervisory advise failed — forget it so the next write retries the advise, and report
|
||||
// failure so the caller fails the write closed (the raw Write would not commit).
|
||||
_supervisedHandles.TryRemove(itemHandle, out _);
|
||||
_logger.LogWarning(
|
||||
"GalaxyDriver supervisory advise failed for item {ItemHandle}: {Code} {Message}",
|
||||
itemHandle, proto.Code, proto.Message);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user