Skip to content

fix(storage): await Worker join in test beforeEach under isolate - #827

Open
Wibias wants to merge 6 commits into
lidge-jun:devfrom
Wibias:fix/storage-worker-isolate-beforeeach
Open

fix(storage): await Worker join in test beforeEach under isolate#827
Wibias wants to merge 6 commits into
lidge-jun:devfrom
Wibias:fix/storage-worker-isolate-beforeeach

Conversation

@Wibias

@Wibias Wibias commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Storage suites no longer sync-reset Workers in beforeEach (fire-and-forget terminate raced the next spawn under Windows bun test --isolate).
  • installPolicyApiHarness / mutation-race / responsive suites await *ForTestsAsync + drainStorageWorkers on setup and teardown.
  • Regression: async beforeEach-style join between spawn cycles in storage-worker-teardown-isolate.test.ts.

Follow-up to #813 after #653 Windows CI still hit workers_spawned(11) workers_terminated(10) mid-storage-mutation-race on tip that already included #813.

Test plan

  • bun test focused storage isolate/mutation/policy suites (22 pass)
  • CI Cross-platform (esp. windows-latest with bun test --isolate tests)
  • After merge, rebase/retarget open PRs that were failing on the same panic (e.g. feat(providers): add Baseten Model APIs preset #653)

Summary by CodeRabbit

  • Bug Fixes

    • Improved storage worker cleanup during test setup and teardown.
    • Reduced race conditions during isolated test cleanup, particularly on Windows.
    • Increased reliability of worker shutdown under heavier test workloads.
    • Added verification that workers are fully stopped between test cycles.
  • Tests

    • Updated storage-related tests to use asynchronous reset and cleanup workflows.
    • Added coverage for repeated worker teardown and isolated environment scenarios.
  • Documentation

    • Documented recommendations for using awaitable reset helpers in tests.

Sync resets were fire-and-forget terminating storage Workers between cases, leaving workers_spawned(N) workers_terminated(N-1) for Windows bun test --isolate. Suites now await async reset + drain, with a mutation-race-style regression.
@github-actions github-actions Bot added the bug Something isn't working label Aug 1, 2026
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Wibias, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 31 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f99b52e2-4d11-4992-a708-4d80b2eea57f

📥 Commits

Reviewing files that changed from the base of the PR and between cc08831 and 4ef29c8.

📒 Files selected for processing (3)
  • src/server/lifecycle.ts
  • src/storage/policy-job.ts
  • src/storage/restore-job.ts
📝 Walkthrough

Walkthrough

The change makes storage test setup and teardown await reset operations, drain workers, and coordinate server shutdown. Policy API harness installation is asynchronous. Isolation tests validate repeated cleanup cycles. The Windows worker join delay increases to 750 ms.

Changes

Storage worker lifecycle

Layer / File(s) Summary
Async reset contracts and worker ordering
src/storage/policy-job.ts, src/storage/restore-job.ts, src/storage/worker-lifecycle.ts
Reset helpers document fire-and-forget behavior. Restore-job reset drains workers before coordinator cleanup. The Windows join delay increases from 250 ms to 750 ms.
Policy API harness lifecycle
tests/helpers/storage-policy-api.ts
Harness installation and cleanup await job resets and worker draining. Failure paths restore environment and temporary resources. stopPolicyServer drains workers before shutdown.
Policy API test setup and teardown
tests/api-storage-policy*.test.ts
Tests await harness installation and use stopPolicyServer for cleanup.
Storage race and responsiveness teardown
tests/storage-mutation-race.test.ts, tests/storage-policy-job-responsive.test.ts, tests/storage-restore-job-responsive.test.ts
Tests await resets, stop or cancel pending work, drain workers, and use coordinated server shutdown.
Isolated worker teardown validation
tests/storage-worker-teardown-isolate.test.ts
Tests assert that repeated asynchronous reset cycles leave no live workers.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: chore

Suggested reviewers: lidge-jun, ingwannu

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. 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 describes the main fix: awaiting Worker termination during isolated storage tests.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/storage/restore-job.ts`:
- Around line 77-80: The reset operations clear shared coordination state before
storage workers finish, so move them until after worker termination, draining,
and asynchronous policy reset complete. In src/storage/restore-job.ts lines
77-80, update the reset flow around resetRestoreTrashJobForTestsAsync,
terminateStorageWorker, and drainStorageWorkers so
resetStorageMutationCoordinatorForTests runs in a finally block after cleanup.
In tests/storage-mutation-race.test.ts lines 166-170 and 174-177, move
resetArchivedCleanupJobForTests after the asynchronous policy reset and final
worker drain in both setup and teardown.

In `@tests/helpers/storage-policy-api.ts`:
- Around line 113-124: Make installPolicyApiHarness drain and reset existing
storage workers before allocating temporary homes or modifying OPENCODEX_HOME,
and wrap setup so any rejection cleans up resources and restores the prior
environment before rethrowing. Update uninstallPolicyApiHarness so
resetStorageCleanupPolicyJobForTestsAsync and drainStorageWorkers cannot bypass
restoration and temporary-directory removal; place teardown cleanup in a finally
block while preserving normal behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5fd1451f-a2c2-48c8-8f80-185c97d4e601

📥 Commits

Reviewing files that changed from the base of the PR and between 6d54e5f and 4bdf451.

📒 Files selected for processing (12)
  • src/storage/policy-job.ts
  • src/storage/restore-job.ts
  • tests/api-storage-policy-already-running.test.ts
  • tests/api-storage-policy-mutation-busy.test.ts
  • tests/api-storage-policy-put-race.test.ts
  • tests/api-storage-policy-run.test.ts
  • tests/api-storage-policy.test.ts
  • tests/helpers/storage-policy-api.ts
  • tests/storage-mutation-race.test.ts
  • tests/storage-policy-job-responsive.test.ts
  • tests/storage-restore-job-responsive.test.ts
  • tests/storage-worker-teardown-isolate.test.ts

Comment thread src/storage/restore-job.ts
Comment thread tests/helpers/storage-policy-api.ts
@Wibias
Wibias marked this pull request as draft August 1, 2026 01:31
Bare server.stop left the policy scheduler armed and skipped the Windows
Worker settle path, so bun test --isolate still panicked with
workers_spawned(N) workers_terminated(N-1) under CI load.

@Ingwannu Ingwannu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Windows CI result is green and the async-join direction is valuable, but two lifecycle issues remain on current head 10ab2e8. (1) restore-job and mutation-race reset shared coordination/archive state before worker termination and the final drain finish, allowing the next test run to acquire a cleared slot while an old worker can still mutate CODEX_HOME; move those resets after cleanup in finally. (2) installPolicyApiHarness mutates OPENCODEX_HOME and allocates temp homes before the first awaited reset, while install/uninstall lack finally-based restoration, so a rejected reset/drain leaks environment and directories. Keep this draft until both order and exception-safety paths are fixed and covered.

@Wibias
Wibias marked this pull request as ready for review August 1, 2026 10:23
@Wibias
Wibias marked this pull request as draft August 1, 2026 10:23
Owner review on lidge-jun#827: keep the coordinator/archive slot held until
terminate+drain finish, and make the policy API harness drain before
OPENCODEX_HOME mutation with finally-based env/temp restore.
@Wibias
Wibias marked this pull request as ready for review August 1, 2026 10:37

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cc08831ac5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

export { fetch, startServer, setStorageCleanupPolicyJobTestHooks, setArchivedCleanupJobTestHooks, stopStorageCleanupScheduler, resetStorageCleanupPolicyJobForTestsAsync };
/** Prefer over Bun.serve.stop — joins Workers and clears the policy scheduler. */
export async function stopPolicyServer(server: ReturnType<typeof startServer>): Promise<void> {
await drainAndShutdown(server, 5_000);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Await the Bun server's stop promise

When these suites reach an isolate boundary, stopPolicyServer() can return before the listener has actually closed: drainAndShutdown() invokes s?.stop(true) at src/server/lifecycle.ts:124 without awaiting the Promise<void> returned by Bun's Server.stop. Replacing the previous await server.stop(true) therefore leaves asynchronous server teardown racing the next test or realm reclamation, undermining the Windows teardown fix. Await s.stop(true) inside drainAndShutdown (or explicitly await it here) before returning.

AGENTS.md reference: AGENTS.md:L157-L159

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[shipping-github] Fixed on tip: drainAndShutdown now awaits s.stop(true) so Bun's Promise<void> close finishes before return (same contract as the previous await server.stop(true) call sites).

Wibias added 2 commits August 1, 2026 12:47
stopPolicyServer switched isolate suites onto drainAndShutdown, which
called stop without awaiting Promise<void> and raced the next realm.
Sync reset/abort released the mutation slot without bumping the spawn-gate epoch, so a gated Worker could still start after coordination was torn down.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants