fix(store-and-forward): resolve StoreAndForward-003, re-triage 002 — fix retry-count off-by-one

This commit is contained in:
Joseph Doherty
2026-05-16 19:57:28 -04:00
parent 09b4bd5dfa
commit 71c0564ec0
4 changed files with 101 additions and 14 deletions

View File

@@ -20,10 +20,14 @@ public class StoreAndForwardMessage
/// <summary>JSON-serialized payload containing the call details.</summary>
public string PayloadJson { get; set; } = string.Empty;
/// <summary>Number of delivery attempts so far.</summary>
/// <summary>
/// Number of retry-sweep attempts performed so far. The initial (immediate or
/// caller-made) delivery attempt is attempt 0 and is not counted here; this
/// field counts only background retry attempts (StoreAndForward-003).
/// </summary>
public int RetryCount { get; set; }
/// <summary>Maximum retry attempts before parking (0 = no limit).</summary>
/// <summary>Maximum retry-sweep attempts before parking (0 = no limit).</summary>
public int MaxRetries { get; set; }
/// <summary>Retry interval in milliseconds.</summary>

View File

@@ -148,13 +148,14 @@ public class StoreAndForwardService
}
catch (Exception ex)
{
// Transient failure — buffer for retry
// Transient failure — buffer for retry. The immediate attempt is
// attempt 0; RetryCount tracks only sweep retries, so it stays 0
// here (StoreAndForward-003).
_logger.LogWarning(ex,
"Immediate delivery to {Target} failed (transient), buffering for retry",
target);
message.LastAttemptAt = DateTimeOffset.UtcNow;
message.RetryCount = 1;
message.LastError = ex.Message;
await BufferAsync(message);
@@ -165,11 +166,11 @@ public class StoreAndForwardService
// Either no handler is registered yet, or the caller already attempted
// delivery itself — buffer for the background retry sweep to deliver.
// The initial attempt (caller-made, or skipped because no handler is
// registered) is attempt 0; RetryCount tracks only sweep retries and
// therefore stays 0 here (StoreAndForward-003).
if (!attemptImmediateDelivery)
{
// The caller made (and failed) one attempt before handing the
// message over, so it counts as the first retry.
message.RetryCount = 1;
message.LastAttemptAt = DateTimeOffset.UtcNow;
}
await BufferAsync(message);