Skip to content

Commit 676a07c

Browse files
authored
fix: render detailed error message for failed to create a graph (#418)
* chore(base_rt): add a dependency * chore: update `Cargo.lock` * fix: render detailed error message for failed to create a graph * chore: add an integration test for graph errors
1 parent 0cd9d43 commit 676a07c

File tree

12 files changed

+143
-36
lines changed

12 files changed

+143
-36
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/base/src/rt_worker/implementation/default_handler.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ use tokio::sync::oneshot::Receiver;
1313

1414
impl WorkerHandler for Worker {
1515
fn handle_error(&self, error: Error) -> Result<WorkerEvents, Error> {
16-
log::error!("{}", error);
16+
log::error!("{}", format!("{error:#}"));
1717
Ok(WorkerEvents::BootFailure(BootFailureEvent {
18-
msg: error.to_string(),
18+
msg: format!("{error:#}"),
1919
}))
2020
}
2121

crates/base/src/rt_worker/worker.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ use crate::rt_worker::supervisor;
44
use crate::rt_worker::utils::{get_event_metadata, parse_worker_conf};
55
use crate::rt_worker::worker_ctx::create_supervisor;
66
use crate::utils::send_event_if_event_worker_available;
7-
use anyhow::{anyhow, Error};
7+
use anyhow::Error;
88
use base_mem_check::MemCheckState;
9+
use base_rt::error::CloneableError;
910
use event_worker::events::{
1011
EventLoopCompletedEvent, EventMetadata, ShutdownEvent, ShutdownReason, UncaughtExceptionEvent,
1112
WorkerEventWithMetadata, WorkerEvents, WorkerMemoryUsed,
@@ -313,10 +314,10 @@ impl Worker {
313314
Err(err) => {
314315
drop(permit);
315316

316-
let _ = booter_signal
317-
.send(Err(anyhow!("worker boot error: {err}")));
317+
let err = CloneableError::from(err.context("worker boot error"));
318+
let _ = booter_signal.send(Err(err.clone().into()));
318319

319-
method_cloner.handle_error(err)
320+
method_cloner.handle_error(err.into())
320321
}
321322
};
322323

crates/base/src/rt_worker/worker_ctx.rs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -640,19 +640,7 @@ pub async fn create_worker<Opt: Into<CreateWorkerArgs>>(
640640
});
641641

642642
// wait for worker to be successfully booted
643-
let worker_boot_result = worker_boot_result_rx.await?;
644-
645-
match worker_boot_result {
646-
Err(err) => {
647-
worker_req_handle.abort();
648-
649-
if let Some(token) = maybe_termination_token.as_ref() {
650-
token.outbound.cancel();
651-
}
652-
653-
bail!(err)
654-
}
655-
643+
match worker_boot_result_rx.await? {
656644
Ok(metric) => {
657645
let elapsed = worker_struct_ref
658646
.worker_boot_start_time
@@ -673,6 +661,15 @@ pub async fn create_worker<Opt: Into<CreateWorkerArgs>>(
673661
exit,
674662
})
675663
}
664+
Err(err) => {
665+
worker_req_handle.abort();
666+
667+
if let Some(token) = maybe_termination_token.as_ref() {
668+
token.outbound.cancel();
669+
}
670+
671+
Err(err)
672+
}
676673
}
677674
} else {
678675
bail!("Unknown")

crates/base/src/rt_worker/worker_pool.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -452,11 +452,10 @@ impl WorkerPool {
452452

453453
status.demand.fetch_add(1, Ordering::Release);
454454
}
455-
Err(e) => {
456-
if tx.send(Err(e)).is_err() {
455+
Err(err) => {
456+
error!("{err:#}");
457+
if tx.send(Err(err)).is_err() {
457458
error!("main worker receiver dropped")
458-
} else {
459-
error!("An error has occured")
460459
}
461460
}
462461
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Relative import path "oak" not prefixed with / or ./ or ../
2+
import "oak";
3+
export default {
4+
fetch() {
5+
return new Response("meow");
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Module not found "file:///.../meow.ts
2+
import "../meow.ts";
3+
export default {
4+
fetch() {
5+
return new Response("meow");
6+
}
7+
}

crates/base/tests/integration_tests.rs

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -906,9 +906,7 @@ async fn test_worker_boot_with_0_byte_eszip() {
906906
let result = create_test_user_worker(opts).await;
907907

908908
assert!(result.is_err());
909-
assert!(result
910-
.unwrap_err()
911-
.to_string()
909+
assert!(format!("{:#}", result.unwrap_err())
912910
.starts_with("worker boot error: unexpected end of file"));
913911
}
914912

@@ -934,10 +932,9 @@ async fn test_worker_boot_with_invalid_entrypoint() {
934932
let result = create_test_user_worker(opts).await;
935933

936934
assert!(result.is_err());
937-
assert!(result
938-
.unwrap_err()
939-
.to_string()
940-
.starts_with("worker boot error: failed to read path"));
935+
assert!(
936+
format!("{:#}", result.unwrap_err()).starts_with("worker boot error: failed to read path")
937+
);
941938
}
942939

943940
#[tokio::test]
@@ -1552,11 +1549,6 @@ async fn test_decorators(ty: Option<DecoratorType>) {
15521549
);
15531550
}
15541551

1555-
#[derive(Deserialize)]
1556-
struct ErrorResponsePayload {
1557-
msg: String,
1558-
}
1559-
15601552
#[tokio::test]
15611553
#[serial]
15621554
async fn test_decorator_should_be_syntax_error() {
@@ -2348,6 +2340,71 @@ async fn test_issue_420() {
23482340
);
23492341
}
23502342

2343+
#[tokio::test]
2344+
#[serial]
2345+
async fn test_should_render_detailed_failed_to_create_graph_error() {
2346+
{
2347+
integration_test!(
2348+
"./test_cases/main",
2349+
NON_SECURE_PORT,
2350+
"graph-error-1",
2351+
None,
2352+
None,
2353+
None,
2354+
None,
2355+
(|resp| async {
2356+
let (payload, status) = ErrorResponsePayload::assert_error_response(resp).await;
2357+
2358+
assert_eq!(status, 500);
2359+
assert!(payload.msg.starts_with(
2360+
"InvalidWorkerCreation: worker boot error: failed to create the graph: \
2361+
Relative import path \"oak\" not prefixed with"
2362+
));
2363+
}),
2364+
TerminationToken::new()
2365+
);
2366+
}
2367+
2368+
{
2369+
integration_test!(
2370+
"./test_cases/main",
2371+
NON_SECURE_PORT,
2372+
"graph-error-2",
2373+
None,
2374+
None,
2375+
None,
2376+
None,
2377+
(|resp| async {
2378+
let (payload, status) = ErrorResponsePayload::assert_error_response(resp).await;
2379+
2380+
assert_eq!(status, 500);
2381+
assert!(payload.msg.starts_with(
2382+
"InvalidWorkerCreation: worker boot error: failed to create the graph: \
2383+
Module not found \"file://"
2384+
));
2385+
}),
2386+
TerminationToken::new()
2387+
);
2388+
}
2389+
}
2390+
2391+
#[derive(Deserialize)]
2392+
struct ErrorResponsePayload {
2393+
msg: String,
2394+
}
2395+
2396+
impl ErrorResponsePayload {
2397+
async fn assert_error_response(resp: Result<Response, reqwest::Error>) -> (Self, u16) {
2398+
let res = resp.unwrap();
2399+
let status = res.status().as_u16();
2400+
let res = res.json::<Self>().await;
2401+
2402+
assert!(res.is_ok());
2403+
2404+
(res.unwrap(), status)
2405+
}
2406+
}
2407+
23512408
trait AsyncReadWrite: AsyncRead + AsyncWrite + Send + Unpin {}
23522409

23532410
impl<T> AsyncReadWrite for T where T: AsyncRead + AsyncWrite + Send + Unpin {}

crates/base_rt/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ version = "0.1.0"
44
edition = "2021"
55

66
[dependencies]
7+
deno_core.workspace = true
8+
79
tokio.workspace = true
810
once_cell.workspace = true
911
tokio-util = { workspace = true, features = ["rt"] }

crates/base_rt/src/error.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use std::sync::Arc;
2+
3+
use deno_core::anyhow;
4+
5+
#[derive(Clone)]
6+
pub struct CloneableError {
7+
inner: Arc<anyhow::Error>,
8+
}
9+
10+
impl From<anyhow::Error> for CloneableError {
11+
fn from(value: anyhow::Error) -> Self {
12+
Self {
13+
inner: Arc::new(value),
14+
}
15+
}
16+
}
17+
18+
impl std::fmt::Display for CloneableError {
19+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20+
self.inner.fmt(f)
21+
}
22+
}
23+
24+
impl std::fmt::Debug for CloneableError {
25+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26+
self.inner.fmt(f)
27+
}
28+
}
29+
30+
impl std::error::Error for CloneableError {
31+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
32+
self.inner.source()
33+
}
34+
}

0 commit comments

Comments
 (0)