fix(telegram): retry stale/missed notification on transient network error - #40
Conversation
|
| Filename | Overview |
|---|---|
| Common/src/main/java/tk/glucodata/TelegramStaleCheckWork.kt | Removes scheduleInternal/retryFor overload and replaces the per-recipient filter with STALE_THROTTLE_MS = 70_000L; the new throttle correctly prevents duplicate STALE posts on the 60 s retry cycle while allowing STALE→MISSED promotion once the throttle window expires. Logic is sound with one style nit: STALE_THROTTLE_MS should be derived from TRANSIENT_RETRY_DELAY_MS to make the invariant self-enforcing. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A([schedule fires]) --> B[load config / recipients]
B --> C{for each recipient}
C --> D{elapsedMs >= staleThreshold?}
D -- No --> E[continue]
D -- Yes --> F{>= missedThreshold?}
F -- Yes --> G[status = MISSED]
F -- No --> H[status = STALE]
G --> I{lastStaleMs > 0 AND now - lastStaleMs < STALE_THROTTLE_MS 70s?}
H --> I
I -- Yes throttled --> E
I -- No --> J[postEdit]
J -- true 2xx --> K[recordStaleAt now]
K --> L{status == STALE?}
L -- Yes --> M[earliestNextDelayMs = min remaining+SLACK]
L -- No MISSED --> N[no reschedule needed]
J -- false 4xx --> O[clearRecipientState]
J -- null transient --> P[earliestNextDelayMs = min 60 s]
M --> C
N --> C
O --> C
P --> C
C -- done --> Q{earliestNextDelayMs < MAX_VALUE?}
Q -- Yes --> R[schedule context delay]
Q -- No --> S([exit no retry])
Reviews (4): Last reviewed commit: "fix(telegram): restore transient retry w..." | Re-trigger Greptile
|
Root cause identified and fixed directly on glucodroid (563126f). The transient-retry logic from this branch has been merged into glucodroid — closing to keep the PR list clean. |
|
Want your agent to iterate on Greptile's feedback? Try greploops. |
…sed approach The scheduleInternal/retryFor mechanism introduced in the previous commit permanently suppressed missed-threshold promotion for recipients that succeeded while another recipient kept failing transiently: the guard `if (retryFor.isNotEmpty() && recipient !in retryFor) continue` skipped all evaluation for unaffected recipients on every 60 s retry, so their STALE→MISSED transition was never triggered. Fix: drop scheduleInternal and retryFor entirely. All recipients are re-evaluated on every invocation. The new STALE_THROTTLE_MS = 70 s (> TRANSIENT_RETRY_DELAY_MS = 60 s) ensures a recipient that just posted STALE is naturally skipped during the 60 s retry cycle, while still being re-evaluated when the missed-threshold timer fires (which can be several minutes later). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…filtering The previous commit was modified by the pre-commit hook and lost two critical pieces: the transient-error retry scheduling and the raised throttle constant. This commit restores both: - TRANSIENT_RETRY_DELAY_MS = 60 s (retry interval on network failure) - STALE_THROTTLE_MS = 70 s (> retry interval, so a recipient that just posted STALE is throttled on the 60 s retry cycle but re-evaluated when the missed-threshold timer fires minutes later) - null branch reschedules at TRANSIENT_RETRY_DELAY_MS instead of silently dropping the notification No retryFor/scheduleInternal — all recipients are re-evaluated on every invocation; the throttle naturally suppresses recently-succeeded ones. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
21f613b to
01ea0c7
Compare
…AY_MS Addresses greptile style nit from PR #40: STALE_THROTTLE_MS is expressed as TRANSIENT_RETRY_DELAY_MS + 10_000L, making the throttle > retry-delay invariant structurally self-enforcing. Drops the now-redundant usage-site comment that restated the relationship. No behavioral change; value remains 70 000 ms. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…AY_MS Addresses greptile style nit from PR #40: STALE_THROTTLE_MS is expressed as TRANSIENT_RETRY_DELAY_MS + 10_000L, making the throttle > retry-delay invariant structurally self-enforcing. Drops the now-redundant usage-site comment that restated the relationship. No behavioral change; value remains 70 000 ms. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
Addresses greptile P1 on PR #36: when `postEdit()` returned `null` (transient network error), the stale/missed alert was silently dropped with no retry path.
What changed
Merges the missed-threshold reschedule and a 60 s transient-retry delay into a single `earliestNextDelayMs` accumulator. On a transient error the scheduler re-fires in 60 s; if a missed-threshold reschedule is pending for another recipient, the earlier of the two wins.
The initial fix used a `retryFor: Set` filter to avoid re-sending to recipients that already succeeded — but greptile correctly flagged that this permanently suppressed the STALE→MISSED promotion for those recipients when another recipient kept failing transiently.
Final approach: drop `scheduleInternal`/`retryFor` entirely. Instead, `STALE_THROTTLE_MS = 70 s > TRANSIENT_RETRY_DELAY_MS = 60 s` means a recipient that just posted STALE is naturally skipped on the 60 s retry cycle (throttled), but re-evaluated when the missed-threshold timer fires minutes later.
All recipients are re-evaluated on every invocation; the throttle naturally suppresses recently-succeeded ones.
Test plan
🤖 Generated with Claude Code