Skip to content

Commit 954ab6d

Browse files
authored
fix: move markAsBackground to EdgeRuntime.waitUntil (#454)
* fix: move `markAsBackground` to `EdgeRuntime.waitUntil` * chore: fill global definitions as far as possible * stamp: align unit tests
1 parent 3cddc61 commit 954ab6d

File tree

7 files changed

+152
-18
lines changed

7 files changed

+152
-18
lines changed

crates/base/src/deno_runtime.rs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,6 +1614,7 @@ mod test {
16141614
use anyhow::Context;
16151615
use deno_config::JsxImportSourceConfig;
16161616
use deno_core::error::AnyError;
1617+
use deno_core::v8::GetPropertyNamesArgs;
16171618
use deno_core::{serde_json, serde_v8, v8, FastString, ModuleCodeString, PollEventLoopOptions};
16181619
use sb_fs::s3_fs::S3FsConfig;
16191620
use sb_fs::tmp_fs::TmpFsConfig;
@@ -2007,17 +2008,19 @@ mod test {
20072008
let global = context.global(inner_scope);
20082009
let edge_runtime_key: v8::Local<v8::Value> =
20092010
serde_v8::to_v8(inner_scope, "EdgeRuntime").unwrap();
2010-
assert!(!global
2011-
.get(inner_scope, edge_runtime_key)
2012-
.unwrap()
2013-
.is_undefined(),);
2011+
2012+
let edge_runtime_ns = global.get(inner_scope, edge_runtime_key).unwrap();
2013+
2014+
assert!(!edge_runtime_ns.is_undefined());
20142015
}
20152016
}
20162017

2017-
// User Runtime Should not have access to EdgeRuntime
2018+
// User Runtime can access EdgeRuntime, but only with specific APIs.
20182019
#[tokio::test]
20192020
#[serial]
20202021
async fn test_user_runtime_creation() {
2022+
let allowed_apis = vec!["waitUntil"];
2023+
20212024
let mut runtime = RuntimeBuilder::new()
20222025
.set_worker_runtime_conf(WorkerRuntimeOpts::UserWorker(Default::default()))
20232026
.build()
@@ -2030,10 +2033,32 @@ mod test {
20302033
let global = context.global(inner_scope);
20312034
let edge_runtime_key: v8::Local<v8::Value> =
20322035
serde_v8::to_v8(inner_scope, "EdgeRuntime").unwrap();
2033-
assert!(global
2036+
2037+
let edge_runtime_ns = global
20342038
.get(inner_scope, edge_runtime_key)
20352039
.unwrap()
2036-
.is_undefined(),);
2040+
.to_object(inner_scope)
2041+
.unwrap();
2042+
2043+
let edge_runtime_ns_keys = edge_runtime_ns
2044+
.get_property_names(
2045+
inner_scope,
2046+
GetPropertyNamesArgs {
2047+
mode: v8::KeyCollectionMode::OwnOnly,
2048+
index_filter: v8::IndexFilter::SkipIndices,
2049+
..Default::default()
2050+
},
2051+
)
2052+
.unwrap();
2053+
2054+
assert_eq!(edge_runtime_ns_keys.length() as usize, allowed_apis.len());
2055+
2056+
for api in allowed_apis {
2057+
let key = serde_v8::to_v8(inner_scope, api).unwrap();
2058+
let obj = edge_runtime_ns.get(inner_scope, key).unwrap();
2059+
2060+
assert!(!obj.is_undefined());
2061+
}
20372062
}
20382063
}
20392064

crates/base/test_cases/mark-background-task/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export default {
3737
mySlowFunction(10);
3838
// make a promise that waits for 5s, and at the same time, notify the runtime that it should
3939
// wait for this promise.
40-
dispatchEvent(new MyBackgroundTaskEvent(markAsBackgroundTask(sleep(5000))));
40+
dispatchEvent(new MyBackgroundTaskEvent(EdgeRuntime.waitUntil(sleep(5000))));
4141
return new Response();
4242
}
4343
}

crates/sb_core/js/async_hook.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const {
88
let COUNTER = 0;
99
const PROMISES = new Map();
1010

11-
function markAsBackgroundTask(maybePromise) {
11+
function waitUntil(maybePromise) {
1212
if (maybePromise instanceof Promise) {
1313
ops.op_tap_promise_metrics("init");
1414
PROMISES.set(maybePromise, ++COUNTER);
@@ -31,6 +31,6 @@ function installPromiseHook() {
3131
}
3232

3333
export {
34-
markAsBackgroundTask,
34+
waitUntil,
3535
installPromiseHook
3636
}

crates/sb_core/js/bootstrap.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import * as globalInterfaces from 'ext:deno_web/04_global_interfaces.js';
2424
import { SUPABASE_ENV } from 'ext:sb_env/env.js';
2525
import { USER_WORKER_API as ai } from 'ext:sb_ai/js/ai.js';
2626
import 'ext:sb_ai/js/onnxruntime/cache_adapter.js';
27-
import { markAsBackgroundTask, installPromiseHook } from 'ext:sb_core_main_js/js/async_hook.js';
27+
import { waitUntil, installPromiseHook } from 'ext:sb_core_main_js/js/async_hook.js';
2828
import { registerErrors } from 'ext:sb_core_main_js/js/errors.js';
2929
import {
3030
formatException,
@@ -592,10 +592,13 @@ globalThis.bootstrapSBEdge = (opts, extraCtx) => {
592592
/// DISABLE SHARED MEMORY INSTALL MEM CHECK TIMING
593593

594594
if (isUserWorker) {
595-
delete globalThis.EdgeRuntime;
596-
597595
ObjectDefineProperties(globalThis, {
598-
markAsBackgroundTask: nonEnumerable(markAsBackgroundTask),
596+
EdgeRuntime: {
597+
value: {
598+
waitUntil,
599+
},
600+
configurable: true,
601+
},
599602
console: nonEnumerable(
600603
new console.Console((msg, level) => {
601604
return ops.op_user_worker_log(msg, level > 1);

crates/sb_core/js/main_worker.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
import { core, primordials } from 'ext:core/mod.js';
2+
13
import { MAIN_WORKER_API as ai } from 'ext:sb_ai/js/ai.js';
24
import { SUPABASE_USER_WORKERS } from 'ext:sb_user_workers/user_workers.js';
35
import { applySupabaseTag } from 'ext:sb_core_main_js/js/http.js';
4-
import { core } from 'ext:core/mod.js';
56

67
const ops = core.ops;
8+
const { ObjectDefineProperty } = primordials;
79

8-
Object.defineProperty(globalThis, 'EdgeRuntime', {
10+
ObjectDefineProperty(globalThis, 'EdgeRuntime', {
911
get() {
1012
return {
1113
ai,

examples/mark-background-task/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export default {
3737
mySlowFunction(10);
3838
// make a promise that waits for 5s, and at the same time, notify the runtime that it should
3939
// wait for this promise.
40-
dispatchEvent(new MyBackgroundTaskEvent(markAsBackgroundTask(sleep(5000))));
40+
dispatchEvent(new MyBackgroundTaskEvent(EdgeRuntime.waitUntil(sleep(5000))));
4141
return new Response();
4242
}
4343
}

types/global.d.ts

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,105 @@
1-
declare function markAsBackgroundTask<T>(promise: Promise<T>): Promise<T>;
1+
type DecoratorType = "tc39" | "typescript" | "typescript_with_metadata";
2+
3+
interface JsxImportBaseConfig {
4+
defaultSpecifier?: string | null;
5+
module?: string | null;
6+
baseUrl?: string | null;
7+
}
8+
9+
// TODO(Nyannyacha): These two type defs will be provided later.
10+
11+
// deno-lint-ignore no-explicit-any
12+
type S3FsConfig = any;
13+
14+
// deno-lint-ignore no-explicit-any
15+
type TmpFsConfig = any;
16+
17+
interface UserWorkerFetchOptions {
18+
signal?: AbortSignal;
19+
}
20+
21+
interface UserWorkerCreateOptions {
22+
servicePath?: string | null;
23+
envVars?: string[][] | [string, string][] | null;
24+
noModuleCache?: boolean | null;
25+
importMapPath?: string | null;
26+
27+
forceCreate?: boolean | null;
28+
netAccessDisabled?: boolean | null;
29+
allowNet?: string[] | null;
30+
allowRemoteModules?: boolean | null;
31+
customModuleRoot?: string | null;
32+
33+
maybeEszip?: Uint8Array | null;
34+
maybeEntrypoint?: string | null;
35+
maybeModuleCode?: string | null;
36+
37+
memoryLimitMb?: number | null;
38+
lowMemoryMultiplier?: number | null;
39+
workerTimeoutMs?: number | null;
40+
cpuTimeSoftLimitMs?: number | null;
41+
cpuTimeHardLimitMs?: number | null;
42+
43+
decoratorType?: DecoratorType | null;
44+
jsxImportSourceConfig?: JsxImportBaseConfig | null;
45+
46+
s3FsConfig?: S3FsConfig | null;
47+
tmpFsConfig?: TmpFsConfig | null;
48+
49+
context?: { [key: string]: unknown } | null;
50+
}
51+
52+
interface HeapStatistics {
53+
totalHeapSize: number;
54+
totalHeapSizeExecutable: number;
55+
totalPhysicalSize: number;
56+
totalAvailableSize: number;
57+
totalGlobalHandlesSize: number;
58+
usedGlobalHandlesSize: number;
59+
usedHeapSize: number;
60+
mallocedMemory: number;
61+
externalMemory: number;
62+
peakMallocedMemory: number;
63+
}
64+
65+
interface RuntimeMetrics {
66+
mainWorkerHeapStats: HeapStatistics;
67+
eventWorkerHeapStats?: HeapStatistics;
68+
}
69+
70+
interface MemInfo {
71+
total: number;
72+
free: number;
73+
available: number;
74+
buffers: number;
75+
cached: number;
76+
swapTotal: number;
77+
swapFree: number;
78+
}
79+
80+
declare namespace EdgeRuntime {
81+
export namespace ai {
82+
function tryCleanupUnusedSession(): Promise<void>;
83+
}
84+
85+
class UserWorker {
86+
constructor(key: string);
87+
88+
fetch(request: Request, options?: UserWorkerFetchOptions): Promise<Response>;
89+
static create(opts: UserWorkerCreateOptions): Promise<UserWorker>;
90+
}
91+
92+
export function waitUntil<T>(promise: Promise<T>): Promise<T>;
93+
export function getRuntimeMetrics(): Promise<RuntimeMetrics>;
94+
export function applySupabaseTag(src: Request, dest: Request): void;
95+
export function systemMemoryInfo(): MemInfo;
96+
export function raiseSegfault(): void;
97+
98+
export { UserWorker as userWorkers };
99+
}
100+
101+
declare namespace Deno {
102+
export namespace errors {
103+
class WorkerRequestCancelled extends Error { }
104+
}
105+
}

0 commit comments

Comments
 (0)