Skip to content

Commit dc5a137

Browse files
[miniflare] Fix resource leaks during config updates
- Only close/recreate devRegistryDispatcher when the port changes, matching the existing runtimeDispatcher pattern (fixes #13584) - Dispose old InspectorProxy instances before replacing them in updateConnection, preventing leaked WebSockets and keepalive timers (fixes #13585)
1 parent 3355bdc commit dc5a137

File tree

3 files changed

+27
-7
lines changed

3 files changed

+27
-7
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
"miniflare": patch
3+
---
4+
5+
Fix resource leaks during config updates
6+
7+
Two follow-up fixes to the dispose cleanup in #13515:
8+
9+
- Only close and recreate the dev-registry dispatcher when its port actually changes, matching the existing `runtimeDispatcher` behavior. Previously, every config update unconditionally tore down and rebuilt the connection pool, which could cause brief request failures if a registry push was in-flight.
10+
- Dispose old `InspectorProxy` instances before replacing them during `updateConnection()`. Previously, stale proxies were silently discarded, leaking their runtime WebSocket connections and 10-second keepalive interval timers.

packages/miniflare/src/index.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,7 @@ export class Miniflare {
11071107
* Called when the dev registry detects changes to external services.
11081108
*/
11091109
#devRegistryDispatcher?: Dispatcher;
1110+
#devRegistryPort?: number;
11101111

11111112
async #pushRegistryUpdate(retries = 3): Promise<void> {
11121113
if (this.#disposeController.signal.aborted) return;
@@ -2422,14 +2423,19 @@ export class Miniflare {
24222423

24232424
// Set up a direct dispatcher to the dev-registry-proxy socket so we can
24242425
// push registry updates without routing through the entry worker.
2426+
// Only close/recreate when the port actually changes, to avoid tearing
2427+
// down the connection pool while a #pushRegistryUpdate is in-flight.
24252428
const devRegistryPort = maybeSocketPorts.get(SOCKET_DEV_REGISTRY);
2426-
void this.#devRegistryDispatcher?.close().catch(() => {});
2427-
if (devRegistryPort !== undefined) {
2428-
this.#devRegistryDispatcher = new Pool(
2429-
new URL(`http://127.0.0.1:${devRegistryPort}`)
2430-
);
2431-
} else {
2432-
this.#devRegistryDispatcher = undefined;
2429+
if (devRegistryPort !== this.#devRegistryPort) {
2430+
void this.#devRegistryDispatcher?.close().catch(() => {});
2431+
this.#devRegistryPort = devRegistryPort;
2432+
if (devRegistryPort !== undefined) {
2433+
this.#devRegistryDispatcher = new Pool(
2434+
new URL(`http://127.0.0.1:${devRegistryPort}`)
2435+
);
2436+
} else {
2437+
this.#devRegistryDispatcher = undefined;
2438+
}
24332439
}
24342440
if (this.#proxyClient === undefined) {
24352441
this.#proxyClient = new ProxyClient(

packages/miniflare/src/plugins/core/inspector-proxy/inspector-proxy-controller.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,10 @@ export class InspectorProxyController {
289289
id: string;
290290
}[];
291291

292+
// Dispose old proxies before replacing them, so their runtime WebSocket
293+
// connections and keepalive intervals are properly cleaned up.
294+
await Promise.all(this.#proxies.map((proxy) => proxy.dispose()));
295+
292296
this.#proxies = workerdInspectorJson
293297
.map(({ id }) => {
294298
if (!id.startsWith("core:user:")) {

0 commit comments

Comments
 (0)