fix(napi): no hard fail on ThreadsafeFunction::call_async (#1970)

For many reasons, in an app we can end up in a scenario where the thread / task that initially called the ThreadsafeFunction gets interrupted. This means that the receiver would get collected, should a ThreadsafeFunction be awaited on the said thread. This will create an error when the ThreadsafeFunction's callback will be called, and call a napi_fatal_error.

This change makes it so that if the send errors, this error is hidden and thus prevents any hard failure. If a ThreadsafeFunction is called in such a case, its output won't be used, but we'll still run all the logic to ensure it ran properly.

Fixes https://github.com/napi-rs/napi-rs/issues/1665 - cc @Brooooooklyn
This commit is contained in:
Louis 2024-02-22 10:34:10 +01:00 committed by GitHub
parent da99081ccf
commit 5b5f616d81
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -494,9 +494,9 @@ impl<T: 'static> ThreadsafeFunction<T, ErrorStrategy::CalleeHandled> {
callback: Box::new(move |d: Result<JsUnknown>| {
sender
.send(d.and_then(|d| D::from_napi_value(d.0.env, d.0.value)))
.map_err(|_| {
crate::Error::from_reason("Failed to send return value to tokio sender")
})
// The only reason for send to return Err is if the receiver isn't listening
// Not hiding the error would result in a napi_fatal_error call, it's safe to ignore it instead.
.or(Ok(()))
}),
}
})))
@ -591,9 +591,11 @@ impl<T: 'static> ThreadsafeFunction<T, ErrorStrategy::Fatal> {
callback: Box::new(move |d: Result<JsUnknown>| {
d.and_then(|d| {
D::from_napi_value(d.0.env, d.0.value).and_then(move |d| {
sender.send(d).map_err(|_| {
crate::Error::from_reason("Failed to send return value to tokio sender")
})
sender
.send(d)
// The only reason for send to return Err is if the receiver isn't listening
// Not hiding the error would result in a napi_fatal_error call, it's safe to ignore it instead.
.or(Ok(()))
})
})
}),