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
25 changes: 21 additions & 4 deletions crates/base/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1573,8 +1573,9 @@ where
}

let js_runtime = &mut this.js_runtime;
let op_state = js_runtime.op_state();
let cpu_metrics_guard = get_cpu_metrics_guard(
js_runtime.op_state(),
op_state.clone(),
maybe_cpu_usage_metrics_tx,
accumulated_cpu_time_ns,
);
Expand Down Expand Up @@ -1630,15 +1631,22 @@ where
beforeunload_cpu_threshold.load().as_deref().copied()
{
let threshold_ns = (threshold_ms as i128) * 1_000_000;
let accumulated_cpu_time_ns = *accumulated_cpu_time_ns as i128;

if accumulated_cpu_time_ns >= threshold_ns {
if (*accumulated_cpu_time_ns as i128) >= threshold_ns {
beforeunload_cpu_threshold.store(None);

if !state.is_terminated() {
let _cpu_metrics_guard = get_cpu_metrics_guard(
op_state.clone(),
maybe_cpu_usage_metrics_tx,
accumulated_cpu_time_ns,
);

if let Err(err) = MaybeDenoRuntime::DenoRuntime(&mut this)
.dispatch_beforeunload_event(WillTerminateReason::CPU)
{
if state.is_terminated() {
return Poll::Ready(Err(anyhow!("execution terminated")));
}
return Poll::Ready(Err(err));
}
}
Expand All @@ -1662,9 +1670,18 @@ where
beforeunload_mem_threshold.store(None);

if !state.is_terminated() && !mem_state.is_exceeded() {
let _cpu_metrics_guard = get_cpu_metrics_guard(
op_state,
maybe_cpu_usage_metrics_tx,
accumulated_cpu_time_ns,
);

if let Err(err) = MaybeDenoRuntime::DenoRuntime(&mut this)
.dispatch_beforeunload_event(WillTerminateReason::Memory)
{
if state.is_terminated() {
return Poll::Ready(Err(anyhow!("execution terminated")));
}
return Poll::Ready(Err(err));
}
}
Expand Down
40 changes: 40 additions & 0 deletions crates/base/test_cases/issue-func-280/cpu/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
function mySlowFunction(baseNumber) {
console.time("mySlowFunction");
let now = Date.now();
let result = 0;
for (var i = Math.pow(baseNumber, 7); i >= 0; i--) {
result += Math.atan(i) * Math.tan(i);
}
let duration = Date.now() - now;
console.timeEnd("mySlowFunction");
return { result: result, duration: duration };
}

let keep = true;

async function sleep(ms: number) {
return new Promise((res) => {
setTimeout(() => {
res(void 0);
}, ms);
});
}

setInterval(() => {
if (keep) {
mySlowFunction(10);
}
}, 800);

addEventListener("beforeunload", () => {
keep = false;
while (true) {
mySlowFunction(10);
console.log("cpu");
}
});

const never = new Promise(() => {});
EdgeRuntime.waitUntil(never);

Deno.serve((_req) => new Response("Hello, world"));
43 changes: 43 additions & 0 deletions crates/base/test_cases/issue-func-280/mem/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
function mySlowFunction(baseNumber) {
console.time("mySlowFunction");
let now = Date.now();
let result = 0;
for (var i = Math.pow(baseNumber, 7); i >= 0; i--) {
result += Math.atan(i) * Math.tan(i);
}
let duration = Date.now() - now;
console.timeEnd("mySlowFunction");
return { result: result, duration: duration };
}

let keep = true;

async function sleep(ms: number) {
return new Promise((res) => {
setTimeout(() => {
res(void 0);
}, ms);
});
}

const arr: ArrayBuffer[] = [];

setInterval(async () => {
if (keep) {
await sleep(300);
arr.push(new ArrayBuffer(1024 * 1024));
}
}, 800);

addEventListener("beforeunload", () => {
keep = false;
while (true) {
arr.push(new ArrayBuffer(1024 * 1024));
console.log("mem");
}
});

const never = new Promise(() => {});
EdgeRuntime.waitUntil(never);

Deno.serve((_req) => new Response("Hello, world"));
53 changes: 53 additions & 0 deletions crates/base/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2553,6 +2553,59 @@ async fn test_issue_func_205() {
unreachable!("test failed");
}

#[tokio::test]
#[serial]
async fn test_issue_func_280() {
async fn run(func_name: &'static str, reason: ShutdownReason) {
let (tx, mut rx) = mpsc::unbounded_channel();
let tb = TestBedBuilder::new("./test_cases/main")
.with_per_worker_policy(None)
.with_worker_event_sender(Some(tx))
.with_server_flags(ServerFlags {
beforeunload_cpu_pct: Some(90),
beforeunload_memory_pct: Some(90),
..Default::default()
})
.build()
.await;

let resp = tb
.request(|b| {
b.uri("/meow")
.header("x-cpu-time-soft-limit-ms", HeaderValue::from_static("1000"))
.header("x-cpu-time-hard-limit-ms", HeaderValue::from_static("2000"))
.header("x-memory-limit-mb", "30")
.header("x-service-path", format!("issue-func-280/{}", func_name))
.body(Body::empty())
.context("can't make request")
})
.await
.unwrap();

assert_eq!(resp.status().as_u16(), StatusCode::OK);

while let Some(ev) = rx.recv().await {
match ev.event {
WorkerEvents::Log(ev) => {
tracing::info!("{}", ev.msg);
continue;
}
WorkerEvents::Shutdown(ev) => {
tb.exit(Duration::from_secs(TESTBED_DEADLINE_SEC)).await;
assert_eq!(ev.reason, reason);
return;
}
_ => continue,
}
}

unreachable!("test failed");
}

run("cpu", ShutdownReason::CPUTime).await;
run("mem", ShutdownReason::Memory).await;
}

#[tokio::test]
#[serial]
async fn test_should_render_detailed_failed_to_create_graph_error() {
Expand Down