summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorNayeem Rahman <nayeemrmn99@gmail.com>2020-10-20 05:05:42 +0100
committerGitHub <noreply@github.com>2020-10-20 15:05:42 +1100
commit7aba07cc7711adfa774afd8e77695f386127c4bc (patch)
tree3325f296ed175cf61b845fa0673e8356f84913b1 /cli
parent57e95032c898cfdfe795e6924d402fdbe2ae59a8 (diff)
fix(cli/worker): Print error stacks from the origin Worker (#7987)
Fixes #4728
Diffstat (limited to 'cli')
-rw-r--r--cli/ops/worker_host.rs34
-rw-r--r--cli/rt/11_workers.js19
-rw-r--r--cli/rt/99_main.js45
-rw-r--r--cli/tests/073_worker_error.ts5
-rw-r--r--cli/tests/073_worker_error.ts.out5
-rw-r--r--cli/tests/074_worker_nested_error.ts5
-rw-r--r--cli/tests/074_worker_nested_error.ts.out5
-rw-r--r--cli/tests/integration_tests.rs12
-rw-r--r--cli/tests/subdir/worker_error.ts5
-rw-r--r--cli/worker.rs13
10 files changed, 102 insertions, 46 deletions
diff --git a/cli/ops/worker_host.rs b/cli/ops/worker_host.rs
index ad915f7f7..4c344e78d 100644
--- a/cli/ops/worker_host.rs
+++ b/cli/ops/worker_host.rs
@@ -1,5 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+use crate::colors;
use crate::fmt_errors::JsError;
use crate::ops::io::get_stdio;
use crate::permissions::Permissions;
@@ -8,7 +9,9 @@ use crate::tokio_util::create_basic_runtime;
use crate::worker::WebWorker;
use crate::worker::WebWorkerHandle;
use crate::worker::WorkerEvent;
+use deno_core::error::generic_error;
use deno_core::error::AnyError;
+use deno_core::futures::channel::mpsc;
use deno_core::futures::future::FutureExt;
use deno_core::serde_json;
use deno_core::serde_json::json;
@@ -25,7 +28,15 @@ use std::rc::Rc;
use std::sync::Arc;
use std::thread::JoinHandle;
-pub fn init(rt: &mut deno_core::JsRuntime) {
+#[derive(Deserialize)]
+struct HostUnhandledErrorArgs {
+ message: String,
+}
+
+pub fn init(
+ rt: &mut deno_core::JsRuntime,
+ sender: Option<mpsc::Sender<WorkerEvent>>,
+) {
{
let op_state = rt.op_state();
let mut state = op_state.borrow_mut();
@@ -40,6 +51,21 @@ pub fn init(rt: &mut deno_core::JsRuntime) {
);
super::reg_json_sync(rt, "op_host_post_message", op_host_post_message);
super::reg_json_async(rt, "op_host_get_message", op_host_get_message);
+ super::reg_json_sync(
+ rt,
+ "op_host_unhandled_error",
+ move |_state, args, _zero_copy| {
+ if let Some(mut sender) = sender.clone() {
+ let args: HostUnhandledErrorArgs = serde_json::from_value(args)?;
+ sender
+ .try_send(WorkerEvent::Error(generic_error(args.message)))
+ .expect("Failed to propagate error event to parent worker");
+ Ok(json!(true))
+ } else {
+ Err(generic_error("Cannot be called from main worker."))
+ }
+ },
+ );
}
pub type WorkersTable = HashMap<u32, (JoinHandle<()>, WebWorkerHandle)>;
@@ -162,6 +188,12 @@ fn run_worker_thread(
}
if let Err(e) = result {
+ eprintln!(
+ "{}: Uncaught (in worker \"{}\") {}",
+ colors::red_bold("error"),
+ name,
+ e.to_string().trim_start_matches("Uncaught "),
+ );
sender
.try_send(WorkerEvent::TerminalError(e))
.expect("Failed to post message to host");
diff --git a/cli/rt/11_workers.js b/cli/rt/11_workers.js
index 0a726a714..dcf98aee6 100644
--- a/cli/rt/11_workers.js
+++ b/cli/rt/11_workers.js
@@ -3,6 +3,7 @@
((window) => {
const core = window.Deno.core;
+ const { Window } = window.__bootstrap.globalInterfaces;
const { log } = window.__bootstrap.util;
function createWorker(
@@ -142,7 +143,14 @@
if (type === "terminalError") {
this.#terminated = true;
if (!this.#handleError(event.error)) {
- throw Error(event.error.message);
+ if (globalThis instanceof Window) {
+ throw new Error("Unhandled error event reached main worker.");
+ } else {
+ core.jsonOpSync(
+ "op_host_unhandled_error",
+ { message: event.error.message },
+ );
+ }
}
continue;
}
@@ -154,7 +162,14 @@
if (type === "error") {
if (!this.#handleError(event.error)) {
- throw Error(event.error.message);
+ if (globalThis instanceof Window) {
+ throw new Error("Unhandled error event reached main worker.");
+ } else {
+ core.jsonOpSync(
+ "op_host_unhandled_error",
+ { message: event.error.message },
+ );
+ }
}
continue;
}
diff --git a/cli/rt/99_main.js b/cli/rt/99_main.js
index e33264726..d7cf50588 100644
--- a/cli/rt/99_main.js
+++ b/cli/rt/99_main.js
@@ -7,8 +7,8 @@ delete Object.prototype.__proto__;
((window) => {
const core = Deno.core;
const util = window.__bootstrap.util;
- const { illegalConstructorKey } = window.__bootstrap.webUtil;
const eventTarget = window.__bootstrap.eventTarget;
+ const globalInterfaces = window.__bootstrap.globalInterfaces;
const dispatchMinimal = window.__bootstrap.dispatchMinimal;
const build = window.__bootstrap.build;
const version = window.__bootstrap.version;
@@ -192,42 +192,6 @@ delete Object.prototype.__proto__;
core.registerErrorClass("URIError", URIError);
}
- class Window extends EventTarget {
- constructor(key) {
- if (key !== illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
- }
- }
-
- get [Symbol.toStringTag]() {
- return "Window";
- }
- }
-
- class WorkerGlobalScope extends EventTarget {
- constructor(key) {
- if (key != illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
- }
- }
-
- get [Symbol.toStringTag]() {
- return "WorkerGlobalScope";
- }
- }
-
- class DedicatedWorkerGlobalScope extends WorkerGlobalScope {
- constructor(key) {
- if (key != illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
- }
- }
-
- get [Symbol.toStringTag]() {
- return "DedicatedWorkerGlobalScope";
- }
- }
-
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope
const windowOrWorkerGlobalScope = {
Blob: util.nonEnumerable(fetch.Blob),
@@ -277,7 +241,7 @@ delete Object.prototype.__proto__;
};
const mainRuntimeGlobalProperties = {
- Window: util.nonEnumerable(Window),
+ Window: globalInterfaces.windowConstructorDescriptor,
window: util.readOnly(globalThis),
self: util.readOnly(globalThis),
// TODO(bartlomieju): from MDN docs (https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope)
@@ -292,8 +256,9 @@ delete Object.prototype.__proto__;
};
const workerRuntimeGlobalProperties = {
- WorkerGlobalScope: util.nonEnumerable(WorkerGlobalScope),
- DedicatedWorkerGlobalScope: util.nonEnumerable(DedicatedWorkerGlobalScope),
+ WorkerGlobalScope: globalInterfaces.workerGlobalScopeConstructorDescriptor,
+ DedicatedWorkerGlobalScope:
+ globalInterfaces.dedicatedWorkerGlobalScopeConstructorDescriptor,
self: util.readOnly(globalThis),
onmessage: util.writable(onmessage),
onerror: util.writable(onerror),
diff --git a/cli/tests/073_worker_error.ts b/cli/tests/073_worker_error.ts
new file mode 100644
index 000000000..736c4fde6
--- /dev/null
+++ b/cli/tests/073_worker_error.ts
@@ -0,0 +1,5 @@
+const worker = new Worker(
+ new URL("subdir/worker_error.ts", import.meta.url).href,
+ { type: "module", name: "bar" },
+);
+setTimeout(() => worker.terminate(), 30000);
diff --git a/cli/tests/073_worker_error.ts.out b/cli/tests/073_worker_error.ts.out
new file mode 100644
index 000000000..412ab3376
--- /dev/null
+++ b/cli/tests/073_worker_error.ts.out
@@ -0,0 +1,5 @@
+[WILDCARD]error: Uncaught (in worker "bar") Error: foo[WILDCARD]
+ at foo ([WILDCARD])
+ at [WILDCARD]
+error: Uncaught Error: Unhandled error event reached main worker.
+ at Worker.#poll ([WILDCARD])
diff --git a/cli/tests/074_worker_nested_error.ts b/cli/tests/074_worker_nested_error.ts
new file mode 100644
index 000000000..975d897ca
--- /dev/null
+++ b/cli/tests/074_worker_nested_error.ts
@@ -0,0 +1,5 @@
+const worker = new Worker(
+ new URL("073_worker_error.ts", import.meta.url).href,
+ { type: "module", name: "baz" },
+);
+setTimeout(() => worker.terminate(), 30000);
diff --git a/cli/tests/074_worker_nested_error.ts.out b/cli/tests/074_worker_nested_error.ts.out
new file mode 100644
index 000000000..412ab3376
--- /dev/null
+++ b/cli/tests/074_worker_nested_error.ts.out
@@ -0,0 +1,5 @@
+[WILDCARD]error: Uncaught (in worker "bar") Error: foo[WILDCARD]
+ at foo ([WILDCARD])
+ at [WILDCARD]
+error: Uncaught Error: Unhandled error event reached main worker.
+ at Worker.#poll ([WILDCARD])
diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs
index d7786e966..0c11ea75e 100644
--- a/cli/tests/integration_tests.rs
+++ b/cli/tests/integration_tests.rs
@@ -2136,6 +2136,18 @@ fn _066_prompt() {
util::test_pty(args, output, input);
}
+itest!(_073_worker_error {
+ args: "run -A 073_worker_error.ts",
+ output: "073_worker_error.ts.out",
+ exit_code: 1,
+});
+
+itest!(_074_worker_nested_error {
+ args: "run -A 074_worker_nested_error.ts",
+ output: "074_worker_nested_error.ts.out",
+ exit_code: 1,
+});
+
itest!(js_import_detect {
args: "run --quiet --reload js_import_detect.ts",
output: "js_import_detect.ts.out",
diff --git a/cli/tests/subdir/worker_error.ts b/cli/tests/subdir/worker_error.ts
new file mode 100644
index 000000000..495971090
--- /dev/null
+++ b/cli/tests/subdir/worker_error.ts
@@ -0,0 +1,5 @@
+function foo() {
+ throw new Error("foo");
+}
+
+foo();
diff --git a/cli/worker.rs b/cli/worker.rs
index d9d9f61c1..877af3208 100644
--- a/cli/worker.rs
+++ b/cli/worker.rs
@@ -1,5 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+use crate::colors;
use crate::fmt_errors::JsError;
use crate::inspector::DenoInspector;
use crate::inspector::InspectorSession;
@@ -275,7 +276,7 @@ impl MainWorker {
ops::runtime::init(js_runtime, main_module);
ops::fetch::init(js_runtime, program_state.flags.ca_file.as_deref());
ops::timers::init(js_runtime);
- ops::worker_host::init(js_runtime);
+ ops::worker_host::init(js_runtime, None);
ops::random::init(js_runtime, program_state.flags.seed);
ops::reg_json_sync(js_runtime, "op_close", deno_core::op_close);
ops::reg_json_sync(js_runtime, "op_resources", deno_core::op_resources);
@@ -443,11 +444,11 @@ impl WebWorker {
op_state.put::<Permissions>(permissions);
}
- ops::web_worker::init(js_runtime, sender, handle);
+ ops::web_worker::init(js_runtime, sender.clone(), handle);
ops::runtime::init(js_runtime, main_module);
ops::fetch::init(js_runtime, program_state.flags.ca_file.as_deref());
ops::timers::init(js_runtime);
- ops::worker_host::init(js_runtime);
+ ops::worker_host::init(js_runtime, Some(sender));
ops::reg_json_sync(js_runtime, "op_close", deno_core::op_close);
ops::reg_json_sync(js_runtime, "op_resources", deno_core::op_resources);
ops::reg_json_sync(
@@ -510,6 +511,12 @@ impl WebWorker {
}
if let Err(e) = r {
+ eprintln!(
+ "{}: Uncaught (in worker \"{}\") {}",
+ colors::red_bold("error"),
+ worker.name.to_string(),
+ e.to_string().trim_start_matches("Uncaught "),
+ );
let mut sender = worker.internal_channels.sender.clone();
sender
.try_send(WorkerEvent::Error(e))