event loop: count queued concurrent_tasks in is_event_loop_alive() - #36686
event loop: count queued concurrent_tasks in is_event_loop_alive()#36686robobun wants to merge 2 commits into
Conversation
ScriptExecutionContext::postTaskTo (used by the small-input crypto.subtle digest fast path and every WebCrypto work-queue completion) enqueues into EventLoop.concurrent_tasks without a paired ref_concurrently(). The liveness check only looked at the drained el.tasks FIFO and has_pending_refs(), so a process could see zero and exit with a crypto.subtle promise still pending in concurrent_tasks. This is the residual behind #11453: edgedb's rawConn does sock.ref()/await/sock.unref() around reads and runs SCRAM via crypto.subtle in between (Bun exposing a global crypto makes the client pick its browserCrypto adapter). With the TLS socket unref'd during the HMAC/digest work, the only thing holding the loop was the WebCrypto task, which the liveness check did not see. Fixes #11453
|
Warning Review limit reached
Next review available in: 13 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughThe VM event-loop liveness check now includes pending concurrent tasks. Regression tests verify that ChangesEvent-loop liveness
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@test/regression/issue/11453.test.ts`:
- Around line 2-12: Remove the detailed regression and root-cause comments,
retaining only the issue URL comment in test/regression/issue/11453.test.ts.
Remove the fast-path rationale at lines 19-20 and socket-flow rationale at lines
59-61; no direct changes are needed beyond comment removal.
🪄 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
Run ID: e533478f-7f4a-4715-be9c-d6c1647a6d1b
📒 Files selected for processing (2)
src/jsc/VirtualMachine.rstest/regression/issue/11453.test.ts
|
Updated 4:05 AM PT - Aug 1st, 2026
❌ @robobun, your commit c4ac238 has 1 failures in
🧪 To try this PR locally: bunx bun-pr 36686That installs a local version of the PR into your bun-36686 --bun |
|
This PR may be a duplicate of:
🤖 Generated with Claude Code |
|
The Keeping this open as the minimal fix for #11453: it is a strict subset of #36548 on the source side, and the regression test here covers the deterministic |
|
CI on c4ac238 (build 87038): the new
Ready for review; a retrigger will not clear the windows-aarch64 upgrade lane while the release asset is absent. |
|
Closing: the same one-line change (counting queued concurrent tasks in is_event_loop_alive_excluding_immediates) landed on main as part of #37075 on 2026-08-08. test/regression/issue/11453.test.ts from this branch passes unmodified against current main (04148c8, debug build, 3 pass / 0 fail on repeated runs) and against the 1.4.0 canary (da3851e). Closing #11453 as well. |
Fixes the residual silent exit in #11453.
Repro
Before: prints nothing, exits 0. Node prints
resolved.The same gap is what makes
@edgedb/generateintermittently exit 0 right afterConnecting to database...: edgedb'srawConn._waitForMessagedoessock.ref()/await/sock.unref()around each read, and the client runs SCRAM viacrypto.subtlein between (Bun exposes a globalcrypto, so the client'sadapter.crypto.nodepicksbrowserCrypto). With the TLS socketunref()'d during the HMAC/digest work, the only thing that should be holding the loop is the pendingcrypto.subtletask.Cause
ScriptExecutionContext::postTaskToroutes throughBun__queueTaskConcurrentlywhich pushes intoEventLoop.concurrent_tasksand wakes the loop, but takes no ref. Two WebCrypto paths reach here without any other ref:<64byte digest fast path inCryptoAlgorithmSHA{1,224,256,384,512,3}.cpp, which computes the hash synchronously on the main thread and posts the callback viapostTaskTo;dispatchAlgorithmOperation(used bysign/verify/encrypt/decrypt/large digests), whereConcurrentCppTask::run_ownedrunsunref_concurrently()afterpostTaskTohas enqueued the result; between the two there is a window whereconcurrent_ref == 0with the result task sitting only inconcurrent_tasks.is_event_loop_alive_excluding_immediates()checkedel.tasks(the drained FIFO),has_pending_refs()and the platform loop'sactivecounter, but notel.concurrent_tasks. So the run loop could evaluate liveness as false and exit with thecrypto.subtlepromise still pending.run_command.rsalready had a one-off|| tick_concurrent_with_count() > 0guard at the initial post-load check; the mainwhile is_event_loop_alive()loop and the other callers did not.Fix
Include
!el.concurrent_tasks.is_empty()inis_event_loop_alive_excluding_immediates().UnboundedQueue::is_emptyis a singleAcquireload ofback, andpop_batchswapsbackto null, so this is an accurate and cheap read from the main thread.Verification
USE_SYSTEM_BUN=1 bun test test/regression/issue/11453.test.ts: 3 fail (empty stdout, exit 0)bun bd test test/regression/issue/11453.test.ts: 3 passtls.connect+ref/unrefaround reads + 4096crypto.subtle.signiterations): 43/50 before, 50/50 afterFixes #11453