Conversation
…pen handles AfterAll was calling worker.close() with a callback but not awaiting it, so Cucumber resolved the hook immediately leaving the HTTP server, Redis, and DB connections open. Node.js would then hang indefinitely waiting for those handles to close. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Collaborator
Coverage Report for CI Build 24596779791Coverage decreased (-0.3%) to 48.812%Details
Uncovered Changes
Coverage Regressions8 previously-covered lines in 2 files lost coverage.
Coverage Stats
💛 - Coveralls |
Redis client may not be connected when rate limits are disabled in tests, causing disconnect() to throw ClientClosedError. Guard with isOpen check. Also raise AfterAll timeout to 30s to allow server and DB to shut down. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
http.Server.close() waits for keep-alive connections to drain naturally, which can prevent the close callback from ever firing. closeAllConnections() forces them closed immediately so the server shuts down reliably in CI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… tests ReplaySubject(2, 1000) schedules recurring setTimeout calls to evict stale buffered events. These timers outlive the test run and keep Node.js alive after Cucumber finishes, preventing clean process exit on CI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The slidingWindowRateLimiterFactory creates a RedisAdapter singleton that calls client.connect() on first WebSocket connection and has no teardown path. --force-exit ensures the process exits cleanly after tests complete rather than hanging on the open Redis socket. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
--force-exit calls process.exit before nyc flushes coverage, causing integration coverage to drop. Instead, call process.exit(0) at the end of AfterAll after all cleanup awaits complete, giving nyc a clean exit. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…owTime changes These were exploratory fixes for the hang; the actual fix was process.exit(0) in AfterAll after cleanup completes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
process.exit(0) in AfterAll kills the process before Cucumber prints its summary. An unref'd 2s timeout lets Cucumber finish output, then force-exits if the Redis singleton is still keeping the process alive. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add closeCacheClient() to the cache module and call it inside AppWorker.close() after the adapter shuts down. This gives the Redis singleton a proper teardown path instead of relying on test-only workarounds. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Process still hangs after worker.close() + DB destroy. Watchdog fires after 2s, logs all active handles/requests via process._getActiveHandles() so we can identify the culprit, then force-exits. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…loud The --publish flag was uploading test results to reports.cucumber.io via a TLS connection to Cloudflare R2, which kept the process alive after tests completed. Reports are already saved locally as HTML and JSON. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
cameri
approved these changes
Apr 18, 2026
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.
Summary
AfterAllwas callingworker.close(callback)without awaiting it, so Cucumber resolved the hook immediately while the HTTP server, Redis client, and DB connections remained openworker.close()in aPromisesoAfterAllproperly waits for all connections to be torn down before the process exitsRoot cause
worker.close()is callback-based (likehttp.Server.close()). Inside anasyncfunction, calling it without wrapping in aPromisemeans the function returns immediately — the callback never blocks the hook from completing.Test plan
npm run docker:test:integrationand confirm tests exit cleanly without hanging🤖 Generated with Claude Code