andywer / andywer/threads.js

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

Abierto
#439 1 comentario 0 reacciones 0 asignados Ver en GitHub
Lenguaje dominante
TypeScript
Estrellas
3.5k
Forks
173
Métricas de merge de PR
Sin PR fusionados en 30 d

Descripción

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.

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.