Skip to content

fix(core): stop waitAndRetry polling once retries are exhausted - #632

Open
afranzi wants to merge 1 commit into
kibertoad:mainfrom
afranzi:fix/wait-and-retry-stops-after-max-retries
Open

afranzi wants to merge 1 commit into
kibertoad:mainfrom
afranzi:fix/wait-and-retry-stops-after-max-retries

Conversation

@afranzi

@afranzi afranzi commented Oct 9, 2026 •

Copy link
Copy Markdown

Once maxRetryCount is exceeded, waitAndRetry resolves with one last predicateFn() call but does not return. performCheck therefore keeps going and polls every sleepTime forever, long after the caller has moved on.

Impact

deleteQueue(..., waitForConfirmation) uses this to poll ListQueues until the queue is gone. If confirmation takes longer than the retry budget (15 × 20 ms), init() continues and recreates the queue. The leftover loop then never sees an empty list, so it keeps sending ListQueues after close() and after the app shuts down.

In ota-service's test suite, the queue is deleted on every init() because of deleteIfExists in tests. The tests run against an in-process fauxqs. When the suite stops fauxqs, the next poll fails with ECONNREFUSED. That promise was passed to an already-settled resolve, so the rejection goes unhandled and Vitest fails an otherwise green run, intermittently.

Change

  • Add the missing return after the final resolve(predicateFn()).
  • Add test/utils/waitUtils.spec.ts, which covers a predicate that eventually succeeds, one that never does (exactly maxRetryCount + 2 calls, then none), and a final check that rejects.

The two new exhaustion tests fail on main (80 and 6 calls instead of 5) and pass with the fix. The core suite passes: 24 files, 289 tests. biome check and tsc are clean. In ota-service, the same one-line patch took the spec from 8-12 ListQueues calls after teardown per run to 0 across 3 runs.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Fixed retry behavior so waiting operations stop polling after the retry limit is reached and return the result of the final check.
    • Errors from the final check are correctly propagated.

After the last retry, performCheck resolved with a final predicate call but
did not return, so it kept polling every sleepTime forever. When the
predicate is a network call (deleteQueue confirmation), the leftover loop
outlives the caller and its rejections surface as unhandled once the
endpoint goes away.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 423e569d-b2f3-49ac-86f5-60de79724065

📥 Commits

Reviewing files that changed from the base of the PR and between 4bbc2c8 and c38de79.


📒 Files selected for processing (2)
  • packages/core/lib/utils/waitUtils.ts
  • packages/core/test/utils/waitUtils.spec.ts

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.



📝 Walkthrough

Walkthrough

waitAndRetry now stops after resolving the predicate at the retry limit. New tests cover the returned result, rejection, and absence of further polling after exhaustion.

Changes

Retry handling

Layer / File(s) Summary
Retry-limit result handling
packages/core/lib/utils/waitUtils.ts, packages/core/test/utils/waitUtils.spec.ts
performCheck returns after resolving the predicate when the retry limit is exceeded. Tests cover a truthy result, the final false result, rejection, and no further checks.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix


Merge Risk: ⚪ Minimal · up to c38de

No actionable issue remains identified with stopping polling at the retry limit; the change is mergeable after normal checks.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: stopping waitAndRetry polling when retries are exhausted.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.


  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR


  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant