fix: make Application listen promise resolve after aborted#685
fix: make Application listen promise resolve after aborted#685Thesephi wants to merge 14 commits intooakserver:mainfrom
Conversation
|
PS: apologies @kitsonk, I forgot |
There was a problem hiding this comment.
Pull request overview
This PR fixes a critical bug where the Application.listen() promise would never resolve after the server was aborted via an AbortSignal. The issue stemmed from the native HTTP server implementation not properly closing its ReadableStream when the abort signal fired, causing the for await loop in application.ts to hang indefinitely.
Changes:
- Added abort signal handling to close the ReadableStream in the native HTTP server implementation
- Added a premature abort check that rejects the listen promise if the signal is already aborted
- Re-enabled and improved the abort-related test, splitting it into two scenarios: abort before and after the listen event
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| http_server_native.ts | Added abort signal handling to close the ReadableStream controller when aborted, aligning with Bun and Node implementations |
| application.test.ts | Re-enabled previously disabled abort test, added premature abort check test, and added new test for abort after listen event |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
application.test.ts
Outdated
| let timer: number | undefined; | ||
| const raceResult = await Promise.race([ | ||
| new Promise(async (resolve) => { | ||
| await p; | ||
| clearTimeout(timer); |
There was a problem hiding this comment.
The timer variable should be initialized before it's used in the clearTimeout call. If the first promise (the one that awaits p) wins the race, timer will still be undefined when clearTimeout(timer) is called on line 1143. This could lead to unexpected behavior. Consider initializing timer before the Promise.race call or restructuring the cleanup logic.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Hi Oak community / cc @kitsonk,
Edited on 12th Dec 24: should close #686 and close #687
I'm using Oak heavily at work (kudos to all for the cool library of course 😀).
I notice (at current version
v17.1.3) the server listen promise doesn't resolve itself even after alreadyaborted.Naive reproduction attempt:
If we do it like the above, then we never see the last line logged out in the console. This suggests the
await pexpression never resolves (forever staying atpendingstate).I was a bit curious how it behaves differently from the doc, so I dug a bit & it resulted in this PR.
I mark the PR as ready for visibility - always happy to consider alternatives or feedback :)
Side note:
During the process, I also noticed a related unit test was disabled. I think it was disabled due to another (slightly related) reason: the server needs a bit of time to initialize itself, so if we call
abort()right afterlisten()(as done in the originally disabled test), then the signal is alreadyaborted by the time the server initializes, and so we "miss" the chance to properly abort it.To this end, I also re-enabled that test, plus I added another test so we cover both scenarios. The PR content explains better than my words here tho 😀
Thank you everyone for your insights / reviews / discussions / objections etc. 🙌 !