pooledMap can throw uncaught `undefined` when cancelled
- Dominant language
- TypeScript
- Stars
- 3.6k
- Forks
- 681
- PR merge metrics
- No merged PRs in 30d
Description
**Describe the bug**
If `pooledMap` gets canceled, it seems to throw an uncaught `undefined` value. Cancelling can happen due to returning from within the loop body. The `undefined` does not seem to be catchable with a `try {} catch {}` construction.
The lack of a stack trace can make debugging tricky, as the developer may not immediately suspect `pooledMap` to be the source of the issue.
**Steps to Reproduce**
```ts
import { pooledMap } from "https://deno.land/std@0.138.0/async/pool.ts";
Deno.test('cancel pooledMap', async () => {
async function firstNumber() {
for await (const num of pooledMap(4, [100], num => Promise.resolve(num))) {
return num;
}
}
await firstNumber();
});
```
```
> deno test
running 1 test from pooledMap_test.ts
test cancel pooledMap ...
test result: FAILED. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (34ms)
error: Uncaught (in promise) undefined
```
**Expected behavior**
In this specific case, there were no remaining items to map over, so I expected pooledMap to cleanly accept the cancelation. I had a routine where some outputs result in immediately returning a specific value, so it's a bit cleaner to return from the loop body.
Alternatively, if cancellation isn't considered sound, I'd expect `pooledMap` to throw an actual `Error` so that a stack trace is printed.
I'd also expect any error to bubbled through my calling code instead of being uncaught.
**Extra information**
If `poolLimit` is set to `1` (disabling concurrency), then an actual error _is_ thrown. It is still uncaught:
```ts
import { pooledMap } from "https://deno.land/std@0.138.0/async/pool.ts";
Deno.test('cancel pooledMap', async () => {
async function firstNumber() {
for await (const num of pooledMap(1, [100], num => Promise.resolve(num))) {
return num;
}
}
try {
await firstNumber();
} catch (err) {
// attempt to not crash the program
console.log('err:', err);
}
});
```
```
> deno test
running 1 test from pooledMap_test.ts
test cancel pooledMap ...
test result: FAILED. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (26ms)
error: Uncaught (in promise) TypeError: Writable stream is closed or errored.
writer.close();
^
at writableStreamClose (deno:ext/web/06_streams.js:3541:9)
at writableStreamDefaultWriterClose (deno:ext/web/06_streams.js:3778:12)
at WritableStreamDefaultWriter.close (deno:ext/web/06_streams.js:5534:14)
at https://deno.land/std@0.138.0/async/pool.ts:54:14
```
**Environment**
- OS: `Debian GNU/Linux 11 (bullseye)`
- deno version: `1.20.5`
- std version: Found on `0.130.0`, verified on `0.138.0`
Contributor guide
Assessment
This issue has not been assessed yet.