Files
bun.sh/test/regression/issue/server-stop-with-pending-requests.test.ts
robobun 790e5d4a7e fix: prevent assertion failure when stopping server with pending requests (#22070)
## 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>
2025-08-22 22:39:47 -07:00

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();
}
});