mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
## Summary Fixes an assertion failure that occurred when `server.stop()` was called while HTTP requests were still in flight. ## Root Cause The issue was in `jsValueAssertAlive()` at `src/bun.js/api/server.zig:627`, which had an assertion requiring `server.listener != null`. However, `server.stop()` immediately sets `listener` to null, causing assertion failures when pending requests triggered callbacks that accessed the server's JavaScript value. ## Solution Converted the server's `js_value` from `jsc.Strong.Optional` to `jsc.JSRef` for safer lifecycle management: - **On `stop()`**: Downgrade from strong to weak reference instead of calling `deinit()` - **In `finalize()`**: Properly call `deinit()` on the JSRef - **Remove problematic assertion**: JSRef allows safe access to JS value via weak reference even after stop ## Benefits - ✅ No more assertion failures when stopping servers with pending requests - ✅ In-flight requests can still access the server JS object safely - ✅ JS object can be garbage collected when appropriate - ✅ Maintains backward compatibility - no external API changes ## Test plan - [x] Reproduces the original assertion failure - [x] Verifies the fix resolves the issue - [x] Adds regression test to prevent future occurrences - [x] Confirms normal server functionality still works The fix includes a comprehensive regression test at `test/regression/issue/server-stop-with-pending-requests.test.ts`. 🤖 Generated with [Claude Code](https://claude.ai/code) --------- Co-authored-by: Claude Bot <claude-bot@bun.sh> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
53 lines
1.4 KiB
TypeScript
53 lines
1.4 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
|
|
// Regression test for server assertion failure when stopping with pending requests
|
|
// This test ensures that calling server.stop() immediately after making requests
|
|
// (including non-awaited ones) doesn't cause an assertion failure.
|
|
test("server.stop() with pending requests should not cause assertion failure", async () => {
|
|
// Create initial server
|
|
let server = Bun.serve({
|
|
port: 0,
|
|
fetch(req) {
|
|
return new Response("OK");
|
|
},
|
|
});
|
|
|
|
try {
|
|
// Make one awaited request
|
|
await fetch(server.url).catch(() => {});
|
|
|
|
// Make one non-awaited request
|
|
fetch(server.url).catch(() => {});
|
|
|
|
// Stop immediately - this should not cause an assertion failure
|
|
server.stop();
|
|
|
|
// If we get here without crashing, the fix worked
|
|
expect(true).toBe(true);
|
|
} finally {
|
|
// Ensure cleanup in case test fails
|
|
try {
|
|
server.stop();
|
|
} catch {}
|
|
}
|
|
});
|
|
|
|
// Additional test to ensure server still works normally after the fix
|
|
test("server still works normally after jsref changes", async () => {
|
|
let server = Bun.serve({
|
|
port: 0,
|
|
fetch(req) {
|
|
return new Response("Hello World");
|
|
},
|
|
});
|
|
|
|
try {
|
|
const response = await fetch(server.url);
|
|
const text = await response.text();
|
|
expect(text).toBe("Hello World");
|
|
expect(response.status).toBe(200);
|
|
} finally {
|
|
server.stop();
|
|
}
|
|
});
|