Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/base/src/rt_worker/implementation/default_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use tokio::sync::oneshot::Receiver;

impl WorkerHandler for Worker {
fn handle_error(&self, error: Error) -> Result<WorkerEvents, Error> {
log::error!("{}", error);
log::error!("{}", format!("{error:#}"));
Ok(WorkerEvents::BootFailure(BootFailureEvent {
msg: error.to_string(),
msg: format!("{error:#}"),
}))
}

Expand Down
9 changes: 5 additions & 4 deletions crates/base/src/rt_worker/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ use crate::rt_worker::supervisor;
use crate::rt_worker::utils::{get_event_metadata, parse_worker_conf};
use crate::rt_worker::worker_ctx::create_supervisor;
use crate::utils::send_event_if_event_worker_available;
use anyhow::{anyhow, Error};
use anyhow::Error;
use base_mem_check::MemCheckState;
use base_rt::error::CloneableError;
use event_worker::events::{
EventLoopCompletedEvent, EventMetadata, ShutdownEvent, ShutdownReason, UncaughtExceptionEvent,
WorkerEventWithMetadata, WorkerEvents, WorkerMemoryUsed,
Expand Down Expand Up @@ -313,10 +314,10 @@ impl Worker {
Err(err) => {
drop(permit);

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

method_cloner.handle_error(err)
method_cloner.handle_error(err.into())
}
};

Expand Down
23 changes: 10 additions & 13 deletions crates/base/src/rt_worker/worker_ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,19 +640,7 @@ pub async fn create_worker<Opt: Into<CreateWorkerArgs>>(
});

// wait for worker to be successfully booted
let worker_boot_result = worker_boot_result_rx.await?;

match worker_boot_result {
Err(err) => {
worker_req_handle.abort();

if let Some(token) = maybe_termination_token.as_ref() {
token.outbound.cancel();
}

bail!(err)
}

match worker_boot_result_rx.await? {
Ok(metric) => {
let elapsed = worker_struct_ref
.worker_boot_start_time
Expand All @@ -673,6 +661,15 @@ pub async fn create_worker<Opt: Into<CreateWorkerArgs>>(
exit,
})
}
Err(err) => {
worker_req_handle.abort();

if let Some(token) = maybe_termination_token.as_ref() {
token.outbound.cancel();
}

Err(err)
}
}
} else {
bail!("Unknown")
Expand Down
7 changes: 3 additions & 4 deletions crates/base/src/rt_worker/worker_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,11 +452,10 @@ impl WorkerPool {

status.demand.fetch_add(1, Ordering::Release);
}
Err(e) => {
if tx.send(Err(e)).is_err() {
Err(err) => {
error!("{err:#}");
if tx.send(Err(err)).is_err() {
error!("main worker receiver dropped")
} else {
error!("An error has occured")
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions crates/base/test_cases/graph-error-1/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Relative import path "oak" not prefixed with / or ./ or ../
import "oak";
export default {
fetch() {
return new Response("meow");
}
}
7 changes: 7 additions & 0 deletions crates/base/test_cases/graph-error-2/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Module not found "file:///.../meow.ts
import "../meow.ts";
export default {
fetch() {
return new Response("meow");
}
}
81 changes: 69 additions & 12 deletions crates/base/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -906,9 +906,7 @@ async fn test_worker_boot_with_0_byte_eszip() {
let result = create_test_user_worker(opts).await;

assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
assert!(format!("{:#}", result.unwrap_err())
.starts_with("worker boot error: unexpected end of file"));
}

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

assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.starts_with("worker boot error: failed to read path"));
assert!(
format!("{:#}", result.unwrap_err()).starts_with("worker boot error: failed to read path")
);
}

#[tokio::test]
Expand Down Expand Up @@ -1552,11 +1549,6 @@ async fn test_decorators(ty: Option<DecoratorType>) {
);
}

#[derive(Deserialize)]
struct ErrorResponsePayload {
msg: String,
}

#[tokio::test]
#[serial]
async fn test_decorator_should_be_syntax_error() {
Expand Down Expand Up @@ -2348,6 +2340,71 @@ async fn test_issue_420() {
);
}

#[tokio::test]
#[serial]
async fn test_should_render_detailed_failed_to_create_graph_error() {
{
integration_test!(
"./test_cases/main",
NON_SECURE_PORT,
"graph-error-1",
None,
None,
None,
None,
(|resp| async {
let (payload, status) = ErrorResponsePayload::assert_error_response(resp).await;

assert_eq!(status, 500);
assert!(payload.msg.starts_with(
"InvalidWorkerCreation: worker boot error: failed to create the graph: \
Relative import path \"oak\" not prefixed with"
));
}),
TerminationToken::new()
);
}

{
integration_test!(
"./test_cases/main",
NON_SECURE_PORT,
"graph-error-2",
None,
None,
None,
None,
(|resp| async {
let (payload, status) = ErrorResponsePayload::assert_error_response(resp).await;

assert_eq!(status, 500);
assert!(payload.msg.starts_with(
"InvalidWorkerCreation: worker boot error: failed to create the graph: \
Module not found \"file://"
));
}),
TerminationToken::new()
);
}
}

#[derive(Deserialize)]
struct ErrorResponsePayload {
msg: String,
}

impl ErrorResponsePayload {
async fn assert_error_response(resp: Result<Response, reqwest::Error>) -> (Self, u16) {
let res = resp.unwrap();
let status = res.status().as_u16();
let res = res.json::<Self>().await;

assert!(res.is_ok());

(res.unwrap(), status)
}
}

trait AsyncReadWrite: AsyncRead + AsyncWrite + Send + Unpin {}

impl<T> AsyncReadWrite for T where T: AsyncRead + AsyncWrite + Send + Unpin {}
Expand Down
2 changes: 2 additions & 0 deletions crates/base_rt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ version = "0.1.0"
edition = "2021"

[dependencies]
deno_core.workspace = true

tokio.workspace = true
once_cell.workspace = true
tokio-util = { workspace = true, features = ["rt"] }
34 changes: 34 additions & 0 deletions crates/base_rt/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use std::sync::Arc;

use deno_core::anyhow;

#[derive(Clone)]
pub struct CloneableError {
inner: Arc<anyhow::Error>,
}

impl From<anyhow::Error> for CloneableError {
fn from(value: anyhow::Error) -> Self {
Self {
inner: Arc::new(value),
}
}
}

impl std::fmt::Display for CloneableError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.inner.fmt(f)
}
}

impl std::fmt::Debug for CloneableError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.inner.fmt(f)
}
}

impl std::error::Error for CloneableError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.inner.source()
}
}
2 changes: 2 additions & 0 deletions crates/base_rt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use std::num::NonZeroUsize;

use once_cell::sync::Lazy;

pub mod error;

pub const DEFAULT_PRIMARY_WORKER_POOL_SIZE: usize = 2;
pub const DEFAULT_USER_WORKER_POOL_SIZE: usize = 1;

Expand Down
2 changes: 1 addition & 1 deletion crates/sb_workers/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ pub async fn op_user_worker_create(
// channel returns a Result<T, E>, we need to unwrap it first;
let result = result.unwrap();
match result {
Err(e) => Err(custom_error("InvalidWorkerCreation", e.to_string())),
Err(e) => Err(custom_error("InvalidWorkerCreation", format!("{e:#}"))),
Ok(res) => Ok(res.key.to_string()),
}
}
Expand Down