Skip to content

Commit 50eb636

Browse files
authored
fix: improve stability (#406)
* fix(sb_graph): don't propagate unnecessary panic * fix(base): give the runtime an explicit chance to handle an interruption request by the supervisor DESCRIPTION: If we cancel the `termination_request_token` token too early, `DenoRuntime` loses the chance to handle the interruption and may not provide a value for `isolate_memory_usage_rx`, causing the task that called `create_supervisor` to deadlock. `DenoRuntime::run` is returned by canceling the `termination_request_token` token, so the user will see the worker terminated as normal, but it will be reported as `EventLoopCompleted`. * stamp: apply `cargo fmt`
1 parent 8b29aa1 commit 50eb636

File tree

6 files changed

+100
-28
lines changed

6 files changed

+100
-28
lines changed

crates/base/src/rt_worker/worker_ctx.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,8 @@ pub fn create_supervisor(
376376
use deno_core::futures::channel::mpsc;
377377
use deno_core::serde_json::Value;
378378

379+
let termination_request_token = termination_request_token.clone();
380+
379381
base_rt::SUPERVISOR_RT
380382
.spawn_blocking(move || {
381383
let wait_inspector_disconnect_fut = async move {
@@ -452,8 +454,6 @@ pub fn create_supervisor(
452454
})
453455
.await
454456
.unwrap();
455-
} else {
456-
termination_request_token.cancel();
457457
}
458458

459459
// NOTE: If we issue a hard CPU time limit, It's OK because it is
@@ -494,6 +494,11 @@ pub fn create_supervisor(
494494
}
495495
};
496496

497+
if !termination_request_token.is_cancelled() {
498+
termination_request_token.cancel();
499+
waker.wake();
500+
}
501+
497502
// send termination reason
498503
let termination_event = WorkerEvents::Shutdown(ShutdownEvent {
499504
reason,

crates/base/tests/integration_tests.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod integration_test_helper;
44
use http_v02 as http;
55
use hyper_v014 as hyper;
66
use reqwest_v011 as reqwest;
7+
use sb_graph::EszipPayloadKind;
78

89
use std::{
910
borrow::Cow,
@@ -883,6 +884,62 @@ async fn test_worker_boot_invalid_imports() {
883884
.starts_with("worker boot error"));
884885
}
885886

887+
#[tokio::test]
888+
#[serial]
889+
async fn test_worker_boot_with_0_byte_eszip() {
890+
let opts = WorkerContextInitOpts {
891+
service_path: "./test_cases/meow".into(),
892+
no_module_cache: false,
893+
import_map_path: None,
894+
env_vars: HashMap::new(),
895+
events_rx: None,
896+
timing: None,
897+
maybe_eszip: Some(EszipPayloadKind::VecKind(vec![])),
898+
maybe_entrypoint: Some("file:///src/index.ts".to_string()),
899+
maybe_decorator: None,
900+
maybe_module_code: None,
901+
conf: WorkerRuntimeOpts::UserWorker(test_user_runtime_opts()),
902+
static_patterns: vec![],
903+
maybe_jsx_import_source_config: None,
904+
};
905+
906+
let result = create_test_user_worker(opts).await;
907+
908+
assert!(result.is_err());
909+
assert!(result
910+
.unwrap_err()
911+
.to_string()
912+
.starts_with("worker boot error: unexpected end of file"));
913+
}
914+
915+
#[tokio::test]
916+
#[serial]
917+
async fn test_worker_boot_with_invalid_entrypoint() {
918+
let opts = WorkerContextInitOpts {
919+
service_path: "./test_cases/meow".into(),
920+
no_module_cache: false,
921+
import_map_path: None,
922+
env_vars: HashMap::new(),
923+
events_rx: None,
924+
timing: None,
925+
maybe_eszip: None,
926+
maybe_entrypoint: Some("file:///meow/mmmmeeeow.ts".to_string()),
927+
maybe_decorator: None,
928+
maybe_module_code: None,
929+
conf: WorkerRuntimeOpts::UserWorker(test_user_runtime_opts()),
930+
static_patterns: vec![],
931+
maybe_jsx_import_source_config: None,
932+
};
933+
934+
let result = create_test_user_worker(opts).await;
935+
936+
assert!(result.is_err());
937+
assert!(result
938+
.unwrap_err()
939+
.to_string()
940+
.starts_with("worker boot error: failed to read path"));
941+
}
942+
886943
#[tokio::test]
887944
#[serial]
888945
async fn req_failure_case_timeout() {

crates/sb_graph/eszip_migrate.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,9 @@ mod test {
422422
}
423423

424424
async fn test_vfs_npm_registry_migration_1_45_x(buf: Vec<u8>) {
425-
let eszip = payload_to_eszip(EszipPayloadKind::VecKind(buf)).await;
425+
let eszip = payload_to_eszip(EszipPayloadKind::VecKind(buf))
426+
.await
427+
.unwrap();
426428
let migrated = try_migrate_if_needed(eszip).await.unwrap();
427429

428430
let vfs_data = migrated

crates/sb_graph/graph_util.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -412,11 +412,11 @@ pub async fn create_graph(
412412

413413
specifier
414414
} else {
415-
let binding = std::fs::canonicalize(&file).unwrap();
416-
let specifier = binding.to_str().unwrap();
415+
let binding = std::fs::canonicalize(&file).context("failed to read path")?;
416+
let specifier = binding.to_str().context("failed to convert path to str")?;
417417
let format_specifier = format!("file:///{}", specifier);
418418

419-
ModuleSpecifier::parse(&format_specifier).unwrap()
419+
ModuleSpecifier::parse(&format_specifier).context("failed to parse specifier")?
420420
};
421421

422422
let builder = ModuleGraphBuilder::new(emitter_factory, false);

crates/sb_graph/lib.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -597,9 +597,11 @@ impl EszipDataSection {
597597
}
598598
}
599599

600-
pub async fn payload_to_eszip(eszip_payload_kind: EszipPayloadKind) -> LazyLoadableEszip {
600+
pub async fn payload_to_eszip(
601+
eszip_payload_kind: EszipPayloadKind,
602+
) -> Result<LazyLoadableEszip, anyhow::Error> {
601603
match eszip_payload_kind {
602-
EszipPayloadKind::Eszip(eszip) => LazyLoadableEszip::new(eszip, None),
604+
EszipPayloadKind::Eszip(eszip) => Ok(LazyLoadableEszip::new(eszip, None)),
603605
_ => {
604606
let bytes = match eszip_payload_kind {
605607
EszipPayloadKind::JsBufferKind(js_buffer) => Vec::from(&*js_buffer),
@@ -610,7 +612,7 @@ pub async fn payload_to_eszip(eszip_payload_kind: EszipPayloadKind) -> LazyLoada
610612
let mut io = AllowStdIo::new(Cursor::new(bytes));
611613
let mut bufreader = BufReader::new(&mut io);
612614

613-
let eszip = eszip_parse::parse_v2_header(&mut bufreader).await.unwrap();
615+
let eszip = eszip_parse::parse_v2_header(&mut bufreader).await?;
614616

615617
let initial_offset = bufreader.stream_position().await.unwrap();
616618
let data_section = EszipDataSection::new(
@@ -620,7 +622,7 @@ pub async fn payload_to_eszip(eszip_payload_kind: EszipPayloadKind) -> LazyLoada
620622
eszip.options,
621623
);
622624

623-
LazyLoadableEszip::new(eszip, Some(Arc::new(data_section)))
625+
Ok(LazyLoadableEszip::new(eszip, Some(Arc::new(data_section))))
624626
}
625627
}
626628
}
@@ -858,14 +860,21 @@ async fn extract_modules(
858860

859861
pub async fn extract_eszip(payload: ExtractEszipPayload) -> bool {
860862
let output_folder = payload.folder;
861-
let mut eszip =
862-
match eszip_migrate::try_migrate_if_needed(payload_to_eszip(payload.data).await).await {
863-
Ok(v) => v,
864-
Err(_old) => {
865-
error!("eszip migration failed (give up extract job)");
866-
return false;
867-
}
868-
};
863+
let eszip = match payload_to_eszip(payload.data).await {
864+
Ok(v) => v,
865+
Err(err) => {
866+
error!("{err:?}");
867+
return false;
868+
}
869+
};
870+
871+
let mut eszip = match eszip_migrate::try_migrate_if_needed(eszip).await {
872+
Ok(v) => v,
873+
Err(_old) => {
874+
error!("eszip migration failed (give up extract job)");
875+
return false;
876+
}
877+
};
869878

870879
eszip.ensure_read_all().await.unwrap();
871880

crates/sb_module_loader/standalone/mod.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -222,16 +222,15 @@ pub async fn create_module_loader_for_standalone_from_eszip_kind<P>(
222222
where
223223
P: AsRef<Path>,
224224
{
225-
let eszip = match eszip_migrate::try_migrate_if_needed(
226-
payload_to_eszip(eszip_payload_kind).await,
227-
)
228-
.await
229-
{
230-
Ok(v) => v,
231-
Err(_old) => {
232-
bail!("eszip migration failed");
233-
}
234-
};
225+
let eszip =
226+
match eszip_migrate::try_migrate_if_needed(payload_to_eszip(eszip_payload_kind).await?)
227+
.await
228+
{
229+
Ok(v) => v,
230+
Err(_old) => {
231+
bail!("eszip migration failed");
232+
}
233+
};
235234

236235
let maybe_import_map = 'scope: {
237236
if maybe_import_map.is_some() {

0 commit comments

Comments
 (0)