From 4786e1d92dcbdcbe743c5e2be0878c3c4f68e781 Mon Sep 17 00:00:00 2001 From: Liam Murphy <43807659+Liamolucko@users.noreply.github.com> Date: Tue, 20 Apr 2021 00:57:02 +1000 Subject: [PATCH] fix(runtime): handle race condition in postMessage where worker has terminated (#10239) The panic was caused by the lack of an error class mapping for futures::channel::TrySendError, but it shouldn't have been throwing an error in the first place - when a worker has terminated, postMessage should just return. The issue was that the termination message hadn't yet been recieved, so it was carrying on with trying to send the message. This adds another check on the Rust side for if the channel is closed, and if it is the worker is treated as terminated. --- cli/tests/integration_tests.rs | 6 ++++++ cli/tests/workers/nonexistent_worker.out | 3 +++ cli/tests/workers/nonexistent_worker.ts | 5 +++++ runtime/web_worker.rs | 8 ++++++++ 4 files changed, 22 insertions(+) create mode 100644 cli/tests/workers/nonexistent_worker.out create mode 100644 cli/tests/workers/nonexistent_worker.ts diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs index 1252d8500a..d178512c56 100644 --- a/cli/tests/integration_tests.rs +++ b/cli/tests/integration_tests.rs @@ -2497,6 +2497,12 @@ console.log("finish"); exit_code: 1, }); + itest!(nonexistent_worker { + args: "run --allow-read workers/nonexistent_worker.ts", + output: "workers/nonexistent_worker.out", + exit_code: 1, + }); + #[test] fn compiler_api() { let status = util::deno_cmd() diff --git a/cli/tests/workers/nonexistent_worker.out b/cli/tests/workers/nonexistent_worker.out new file mode 100644 index 0000000000..e43b81c5f6 --- /dev/null +++ b/cli/tests/workers/nonexistent_worker.out @@ -0,0 +1,3 @@ +[WILDCARD]error: Uncaught (in worker "") Cannot resolve module "file:///[WILDCARD]cli/tests/workers/doesnt_exist.js". +error: Uncaught (in promise) Error: Unhandled error event reached main worker. + at Worker.#poll ([WILDCARD]) diff --git a/cli/tests/workers/nonexistent_worker.ts b/cli/tests/workers/nonexistent_worker.ts new file mode 100644 index 0000000000..8ebe291145 --- /dev/null +++ b/cli/tests/workers/nonexistent_worker.ts @@ -0,0 +1,5 @@ +const w = new Worker(new URL("doesnt_exist.js", import.meta.url).href, { + type: "module", +}); + +w.postMessage("hello"); diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index 68bbe1a5d9..8c8761d627 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -67,6 +67,14 @@ impl WebWorkerHandle { /// Post message to worker as a host. pub fn post_message(&self, buf: Box<[u8]>) -> Result<(), AnyError> { let mut sender = self.sender.clone(); + // If the channel is closed, + // the worker must have terminated but the termination message has not yet been recieved. + // + // Therefore just treat it as if the worker has terminated and return. + if sender.is_closed() { + self.terminated.store(true, Ordering::SeqCst); + return Ok(()); + } sender.try_send(buf)?; Ok(()) }