Feat/allowance concurrency retry - #998
Merged
orunganiekan merged 2 commits intoAug 31, 2026
Merged
Conversation
…oLabs#97) Add configurable concurrent execution and per-call transient-error retry with backoff to check-allowances.ts and alert-expiring-allowances.ts. Shared logic lives in the new allowance-utils.ts module. New file: scripts/allowance-utils.ts - withRetry<T>(): exponential backoff retry; skips DefinitiveError and known non-transient HTTP patterns (400/401/403/404); retries on network/timeout/5xx/429 - pLimit(n): token-bucket concurrency limiter; rejects limit < 1 - runConcurrent(): fan-out helper that caps in-flight tasks and captures per-task errors without aborting the batch - isTransientError(): classifier for the retry gate - DefinitiveError: marker class for business-logic (non-retryable) results - Stable JSON schema types: AuditResult, AllowanceCheckReport, ExpiryEntry, ExpiryAlertReport scripts/check-allowances.ts: - getSubscription() and getAllowance() now call withRetry() internally; max retries / base delay controlled by MAX_RETRIES / RETRY_BASE_MS env vars - auditSubscriber() runs both RPC calls with retry; definitive outcomes (invalid_address, no_subscription) bypass retry entirely - main() fans out all addresses via runConcurrent(CONCURRENCY) - --json writes AllowanceCheckReport to stdout; human summary always goes to stderr via logger so they never interleave - Stable JSON field names: subscription_amount, allowance, gap, at_risk, error (replaces prior camelCase inconsistency) - New env knobs: CONCURRENCY (default 5), MAX_RETRIES (default 3), RETRY_BASE_MS (default 300) scripts/alert-expiring-allowances.ts: - getSubscription(), getAllowanceAmount(), getAllowanceExpiryLedger() all call withRetry() with the same env knobs - main() fans out via runConcurrent(CONCURRENCY) - Always writes ExpiryAlertReport JSON to stdout; human summary to stderr - Same CONCURRENCY / MAX_RETRIES / RETRY_BASE_MS env knobs scripts/test-allowance-utils.ts (new): 16 test cases, no network required: Suite 1 — isTransientError classification (transient vs definitive) Suite 2 — withRetry succeeds on first attempt Suite 3 — withRetry retries on transient error, recovers Suite 4 — withRetry exhausts retries and rethrows Suite 5 — withRetry does NOT retry DefinitiveError Suite 6 — withRetry does NOT retry 404 non-transient error Suite 7 — withRetry maxRetries=0 propagates immediately Suite 8 — pLimit respects concurrency cap across 10 tasks Suite 9 — pLimit(1) serialises tasks Suite 10 — pLimit(0) throws RangeError Suite 11 — runConcurrent all-success preserves order Suite 12 — runConcurrent partial failures captured as Error objects Suite 13 — runConcurrent concurrency cap respected (20 tasks, cap 4) Suite 14 — mock flaky RPC (4 x 503 then success) round-trip Suite 15 — onRetry callback receives correct 1-based attempt numbers Suite 16 — runConcurrent empty task list returns [] scripts/package.json: - Add test:allowance-utils script Non-goal (explicit): MultiEndpointServer failover is owned by rpc-client.ts (Issue 077) and is reused here unchanged — not reimplemented. Closes SiLioLabs#97
|
@ogaziedaniel80-droid Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #891
Adds configurable bounded concurrency and per-call transient-error retry with backoff to both allowance scripts. A new shared
allowance-utils.tsmodule carries all the reusable logic and stable JSON schema types.New:
scripts/allowance-utils.tswithRetry<T>()— exponential backoff retry with jitter; propagates immediately onDefinitiveErrorand known non-transient HTTP errors (400/401/403/404); retries on network/timeout/5xx/429pLimit(n)— token-bucket concurrency limiter; throwsRangeErroron n < 1runConcurrent()— fan-out helper capping in-flight tasks, captures per-task errors as Error objects without aborting the batchisTransientError()— classifier powering the retry gateDefinitiveError— marker class for non-retryable business-logic resultsAuditResult,AllowanceCheckReport,ExpiryEntry,ExpiryAlertReportscripts/check-allowances.tsgetSubscription()andgetAllowance()usewithRetry()internallyauditSubscriber()— definitive outcomes (invalid_address,no_subscription) bypass retrymain()fans out all addresses viarunConcurrent(CONCURRENCY)--jsonwritesAllowanceCheckReportto stdout; human summary always on stderrCONCURRENCY(default 5),MAX_RETRIES(default 3),RETRY_BASE_MS(default 300)scripts/alert-expiring-allowances.tsmain()fans out viarunConcurrent(CONCURRENCY), same env knobsExpiryAlertReportJSON to stdoutscripts/test-allowance-utils.ts(new, 16 test cases, no network)Suites cover: transient/definitive classification, retry success/exhaustion/no-retry-on-definitive/no-retry-on-404/maxRetries=0,
pLimitconcurrency cap/serialisation/invalid-limit,runConcurrentordering/partial-failures/cap, mock flaky RPC round-trip,onRetrycallback numbering, empty task list.Explicit non-goal: MultiEndpointServer failover is owned by
rpc-client.ts(Issue 077) and is reused here unchanged.Acceptance criteria