fix(notifications): park corrupt buffered notification payloads instead of silently discarding as delivered (supersedes StoreAndForward-018)
This commit is contained in:
@@ -20,6 +20,10 @@ namespace ZB.MOM.WW.ScadaBridge.StoreAndForward;
|
||||
/// <item><description>ack not <c>Accepted</c>, or the Ask times out / fails →
|
||||
/// <see cref="DeliverAsync"/> throws; the S&F engine treats any thrown
|
||||
/// exception as transient and retries the forward at the fixed interval.</description></item>
|
||||
/// <item><description>the buffered payload is corrupt (undeserialisable / null) →
|
||||
/// <see cref="DeliverAsync"/> returns <c>false</c> (the handler contract's
|
||||
/// permanent-failure signal); the engine parks the row so the payload is preserved
|
||||
/// for operator forensics. Supersedes StoreAndForward-018's silent discard.</description></item>
|
||||
/// </list>
|
||||
///
|
||||
/// The forward travels over the ClusterClient command/control transport: the handler
|
||||
@@ -51,8 +55,8 @@ public sealed class NotificationForwarder
|
||||
/// </param>
|
||||
/// <param name="logger">
|
||||
/// Optional logger. A corrupt buffered payload is logged at
|
||||
/// Warning before being discarded so an operator has a forensic trail of the row
|
||||
/// that vanished from the buffer.
|
||||
/// Warning before the row is parked so an operator has a forensic trail pointing at
|
||||
/// the preserved parked row.
|
||||
/// </param>
|
||||
public NotificationForwarder(
|
||||
IActorRef siteCommunicationActor,
|
||||
@@ -69,21 +73,26 @@ public sealed class NotificationForwarder
|
||||
/// <summary>
|
||||
/// Store-and-Forward delivery handler entry point — matches the
|
||||
/// <c>Func<StoreAndForwardMessage, Task<bool>></c> handler contract.
|
||||
/// Returns <c>true</c> when central accepts the notification; throws on a
|
||||
/// non-accepted ack or an Ask timeout/failure so the engine retries.
|
||||
/// Returns <c>true</c> when central accepts the notification; returns <c>false</c>
|
||||
/// when the buffered payload is corrupt (permanent failure → engine parks the row);
|
||||
/// throws on a non-accepted ack or an Ask timeout/failure so the engine retries.
|
||||
/// </summary>
|
||||
/// <param name="message">The buffered store-and-forward message to deliver to central.</param>
|
||||
/// <returns>A task that resolves to <c>true</c> when central accepts (or the payload is corrupt and discarded); throws on a transient forward failure so the engine retries.</returns>
|
||||
/// <returns>A task that resolves to <c>true</c> when central accepts; <c>false</c> when the payload is corrupt (the engine parks the row for forensics); throws on a transient forward failure so the engine retries.</returns>
|
||||
public async Task<bool> DeliverAsync(StoreAndForwardMessage message)
|
||||
{
|
||||
if (!TryBuildSubmit(message, out var submit))
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Discarding corrupt buffered notification {NotificationId} (payload is not deserialisable as NotificationSubmit). " +
|
||||
"Payload preview: {PayloadPreview}",
|
||||
"Parking corrupt buffered notification {NotificationId} (payload is not deserialisable as NotificationSubmit); " +
|
||||
"the row is preserved for operator forensics. Payload preview: {PayloadPreview}",
|
||||
message.Id,
|
||||
PreviewPayload(message.PayloadJson));
|
||||
return true;
|
||||
// false = permanent failure by the delivery-handler contract → the
|
||||
// engine parks the row (payload preserved, operator can inspect or
|
||||
// discard). Supersedes StoreAndForward-018's silent discard, which
|
||||
// reported the notification as delivered while losing it entirely.
|
||||
return false;
|
||||
}
|
||||
|
||||
// The reply may legitimately be a non-accepted ack, so it is not requested as
|
||||
|
||||
Reference in New Issue
Block a user