piscina
piscina copied to clipboard
All errors are upcast to Error in the main thread?
I'm not able to differentiate between specialized error types thrown in workers, as they appear to be upcast to Error in the main thread. This makes specializing error handling in the main thread difficult. Is there any way to work around this?
Code example:
// worker
export class MyError extends Error {
...
}
export default async function() {
throw new MyError();
}
// main
const workerPool = new Piscina({
...
});
try {
workerPool.run()
} catch(error) {
if (error instanceof Error) {
// this code path works
}
if (error instanceof MyError) {
// this code path is never taken
}
}
random guess - maybe serialization for IPC gobbles the type up and captures only the properties? As a workaround for now, what about testing the name
property (or some other custom property)
e.g. apollo's set of errors defines the name explicitly https://github.com/apollographql/apollo-server/blob/12cbe0067fe15796391d8ceeb046acae5776bb74/packages/apollo-server-errors/src/index.ts#L179-L185 and I think apollo server reads from .extensions.code
to classify the error type
It looks like name
just becomes Error
and any custom properties are stripped. It might be possible to parse the message
property to determine the original error name? It would be nice to avoid this though.
Node.js uses the structured clone algorithm for messaging across threads. Custom objects (subclasses, your own class objects, etc) are not supported fully by the structured clone algorithm. Error objects will always come out as the top level built-in Error they extend from (e.g. class MyError extends Error
=> Error
, class MyTypeError extends TypeError
=> TypeError
. Further, on custom class objects, only own properties on the objects are cloned, so if I have class Foo { get a() { return 1 } }; f = new Foo(); f.b = 2
, cloning would yield only { b: 2 }
How to resolve it? In my screen:
// child
const err = new Error('message')
err.skip = true // main thread lost it
throw err
Passing a flag or some way to identify the error is a way to go, but relying on the prototype is not recommended because of the reason @jasnell pointed out 🙂