mirror of
https://github.com/oven-sh/bun
synced 2026-02-15 13:22:07 +00:00
Add Symbol.asyncDispose to Worker in worker_threads (#22064)
## Summary
- Implement `Symbol.asyncDispose` for the `Worker` class in
`worker_threads` module
- Enables automatic resource cleanup with `await using` syntax
- Calls `await this.terminate()` to properly shut down workers when they
go out of scope
## Implementation Details
The implementation adds a simple async method to the Worker class:
```typescript
async [Symbol.asyncDispose]() {
await this.terminate();
}
```
This allows workers to be used with the new `await using` syntax for
automatic cleanup:
```javascript
{
await using worker = new Worker('./worker.js');
// worker automatically terminates when leaving this scope
}
```
## Test Plan
- [x] Added comprehensive tests for `Symbol.asyncDispose` functionality
- [x] Tests verify the method exists and returns undefined
- [x] Tests verify `await using` syntax works correctly for automatic
worker cleanup
- [x] All new tests pass
- [x] Existing worker_threads functionality remains intact
🤖 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>
This commit is contained in:
@@ -388,6 +388,10 @@ class Worker extends EventEmitter {
|
||||
#onOpen() {
|
||||
this.emit("online");
|
||||
}
|
||||
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.terminate();
|
||||
}
|
||||
}
|
||||
|
||||
class HeapSnapshotStream extends Readable {
|
||||
|
||||
58
test/js/node/worker_threads/worker-async-dispose.test.ts
Normal file
58
test/js/node/worker_threads/worker-async-dispose.test.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { Worker } from "worker_threads";
|
||||
|
||||
test("Worker implements Symbol.asyncDispose", async () => {
|
||||
const worker = new Worker(
|
||||
`
|
||||
const { parentPort } = require("worker_threads");
|
||||
parentPort?.postMessage("ready");
|
||||
`,
|
||||
{ eval: true },
|
||||
);
|
||||
|
||||
// Wait for the worker to be ready
|
||||
await new Promise(resolve => {
|
||||
worker.on("message", msg => {
|
||||
if (msg === "ready") {
|
||||
resolve(msg);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Test that Symbol.asyncDispose exists and is a function
|
||||
expect(typeof worker[Symbol.asyncDispose]).toBe("function");
|
||||
|
||||
// Test that calling Symbol.asyncDispose terminates the worker
|
||||
const disposeResult = await worker[Symbol.asyncDispose]();
|
||||
expect(disposeResult).toBeUndefined();
|
||||
});
|
||||
|
||||
test("Worker can be used with await using", async () => {
|
||||
let workerTerminated = false;
|
||||
|
||||
{
|
||||
await using worker = new Worker(
|
||||
`
|
||||
const { parentPort } = require("worker_threads");
|
||||
parentPort?.postMessage("hello from worker");
|
||||
`,
|
||||
{ eval: true },
|
||||
);
|
||||
|
||||
// Listen for worker exit to confirm termination
|
||||
worker.on("exit", () => {
|
||||
workerTerminated = true;
|
||||
});
|
||||
|
||||
// Wait for the worker message to ensure it's running
|
||||
await new Promise(resolve => {
|
||||
worker.on("message", resolve);
|
||||
});
|
||||
|
||||
// Worker should automatically terminate when leaving this block via Symbol.asyncDispose
|
||||
}
|
||||
|
||||
// Give a moment for the exit event to be emitted
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
expect(workerTerminated).toBe(true);
|
||||
});
|
||||
Reference in New Issue
Block a user