andywer / andywer/threads.js

Pool initialization rejections cannot be handled currently, and they return errors in the global main handler of javascript.

Đang mở
#439 1 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
TypeScript
Star
3.5k
Fork
173
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Mô tả

There's no way to handle pool init errors. Consider a scenario where a website's CSP doesn't allow us to run a worker; the pool init will fail to make a handshake with the worker because the worker never gets initialized. If we queue tasks to the pool, then the PromiseLike returned from the `queue` method of the `pool` class is not catchable.

For example, if you have this code:

```ts
let work;
try {
work = new Worker(new URL(`data:text/javascript;base64:${workerJs}`))
} catch (e) {
work = new Worker();
}
const pool = Pool(() =>
spawn(work, {
timeout: 1000,
}),
1
);

const allTasks = [];
for (let i = 0; i < 10; i ++) {
const p = new Promise(async (resolve, reject) => {
try {
const t = await pool.queue((e) => {});
return resolve(t);
} catch (e) {
return reject(e);
}
});
allTasks.push(p.catch(e => {console.log(e)}));
}

// You can never catch it since it always throws errors in the main thread.
await Promise.all(allTasks);
```

## Possible Fix

When a pool fails to init, it inserts an error event to the `eventSubjects` stream:
https://sourcegraph.com/github.com/andywer/threads.js/-/blob/src/master/pool.ts?L151&subtree=true

```
this.eventSubject.error(error)
```

We can't catch the error because the `taskCompletion` method does not subscribe to the error events. It's only subscribing to the `next()` events. Adding a case for the error in the below code appropriately rejects the error.
https://sourcegraph.com/github.com/andywer/threads.js/-/blob/src/master/pool.ts?L233&subtree=true#tab=references

```
// minified.
taskCompletion(e) {
return new Promise((t, r) => {
const n = this.events().subscribe({
next(o) {
o.type === u.PoolEventType.taskCompleted && o.taskID === e
? (n.unsubscribe(), t(o.returnValue))
: o.type === u.PoolEventType.taskFailed && o.taskID === e
? (n.unsubscribe(), r(o.error))
: o.type === u.PoolEventType.terminated &&
(n.unsubscribe(),
r(Error("Pool has been terminated before task was run.")));
},
error: r
});
});
```

I can create a PR with the fix but want to know if I am doing something wrong.

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.