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>| { callback: Box::new(move |d: Result<JsUnknown>| {
sender sender
.send(d.and_then(|d| D::from_napi_value(d.0.env, d.0.value))) .send(d.and_then(|d| D::from_napi_value(d.0.env, d.0.value)))
.map_err(|_| { // The only reason for send to return Err is if the receiver isn't listening
crate::Error::from_reason("Failed to send return value to tokio sender") // 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>| { callback: Box::new(move |d: Result<JsUnknown>| {
d.and_then(|d| { d.and_then(|d| {
D::from_napi_value(d.0.env, d.0.value).and_then(move |d| { D::from_napi_value(d.0.env, d.0.value).and_then(move |d| {
sender.send(d).map_err(|_| { sender
crate::Error::from_reason("Failed to send return value to tokio 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(()))
}) })
}) })
}), }),