Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
befe24b
feat: release deno 2.1 compatible version (#592)
nyannyacha Aug 20, 2025
6084d3b
fix: semantic release version conflict (#593)
nyannyacha Aug 20, 2025
d3b9cee
fix: remove another bottleneck that causes boot time spike (#596)
nyannyacha Aug 26, 2025
1dd5817
fix(ext): handle log level correctly (#599)
nyannyacha Aug 28, 2025
173cad4
fix(deno_facade): don't randomly place contents when bundling (#600)
nyannyacha Aug 28, 2025
8590136
chore(cpu_timer): cleanup code and place cfg attr correctly (#595)
nyannyacha Aug 29, 2025
73628eb
fix(byonm): Deno.readFile* fails to recognize paths correctly when ca…
nyannyacha Sep 1, 2025
917a3b8
fix: add `otel_attributes` to event metadata (#602)
nyannyacha Sep 2, 2025
e29bd12
fix(cli): introduce timeout flag for the bundle command (#603)
nyannyacha Sep 4, 2025
8fd73e6
fix(fs): allow Deno.makeTempFile[Sync] (#604)
nyannyacha Sep 5, 2025
7c9d8da
chore(ci/stale): add an missing permission (#606)
nyannyacha Sep 9, 2025
159fc1d
fix(supervisor): do not try to divide 0 by 2 (#607)
nyannyacha Sep 11, 2025
7b23fd9
stamp: starting with `ai` docs
kallebysantos May 21, 2025
46977c6
stamp: trying with assets
kallebysantos May 21, 2025
e6c9ac0
add: onnxruntime instructions
kallebysantos May 21, 2025
b46df4c
stamp: self-hosting onnxruntime instructions
kallebysantos May 21, 2025
3a4f8bf
stamp: adding `Session` information
kallebysantos May 23, 2025
f050201
stamp: adding useful links to main Readme
kallebysantos May 23, 2025
5024818
stamp: improving
kallebysantos May 23, 2025
ffc69bd
stamp(ai): adding reference to tests folder
kallebysantos May 23, 2025
bdc5d34
stamp: improving edge-runtime diagram
kallebysantos May 26, 2025
8543807
fix: diagram width
kallebysantos May 26, 2025
4fc0a1e
stamp: add diagram caption
kallebysantos May 26, 2025
d6725f7
stamp: add base runtime diagram
kallebysantos Aug 18, 2025
4f2ac6b
feat: add usage section
kallebysantos Sep 12, 2025
eaf2776
stamp: improving usage docs - main service VS user worker
kallebysantos Sep 12, 2025
bef679b
stamp: creating api compatibility table - VALUES NOT VALIDATED
kallebysantos Sep 17, 2025
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
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ jobs:
version: ${{ steps.semantic.outputs.new_release_version }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
fetch-tags: true

- name: Semantic Release
id: semantic
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/stale.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
workflow_dispatch:

permissions:
actions: write
issues: write
pull-requests: write

Expand Down
25 changes: 23 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ Options**

## Architecture

![Sequence diagram of Edge Runtime request flow](assets/edge-runtime-diagram.svg?raw=true)
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="/assets/edge-runtime-diagram-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="/assets/edge-runtime-diagram.svg">
<img alt="Sequence diagram of Edge Runtime request flow" src="/assets/edge-runtime-diagram.svg" style="max-width: 100%;">
</picture>
</p>

The edge runtime can be divided into two runtimes with different purposes.

Expand All @@ -30,7 +36,22 @@ The edge runtime can be divided into two runtimes with different purposes.
- User runtime:
- An instance for the _user runtime_ is responsible for executing users' code.
- Limits are required to be set such as: Memory and Timeouts.
- Has access to environment variables explictly allowed by the main runtime.
- Has access to environment variables explicitly allowed by the main runtime.

### Usage & Self-Hosting

For completely usage and self-host details, visit [usage.md](/docs/usage.md)

### Edge Runtime in Deep

#### Conceptual

- [EdgeRuntime Base](/crates/base/README.md): Overalls about how EdgeRuntime is based on Deno.

#### Extension Modules

- [AI](/ext/ai/README.md): Implements AI related features.
- [NodeJs](/ext/node/README.md) & [NodeJs Polyfills](/ext/node/polyfills/README.md): Implements the NodeJs compatibility layer.

## Developers

Expand Down
4 changes: 4 additions & 0 deletions assets/docs/ai/onnx-backend-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions assets/docs/ai/onnx-backend.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions assets/edge-runtime-diagram-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 4 additions & 21 deletions assets/edge-runtime-diagram.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions cli/src/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,11 @@ fn get_bundle_command() -> Command {
.default_value("false")
.value_parser(FalseyValueParser::new()),
)
.arg(
arg!(--"timeout" <SECONDS>)
.help("Maximum time in seconds that can be waited for the bundle to complete.")
.value_parser(value_parser!(u64).range(..u64::MAX))
)
}

fn get_unbundle_command() -> Command {
Expand Down
22 changes: 19 additions & 3 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::path::PathBuf;
use std::process::ExitCode;
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;

use anyhow::bail;
use anyhow::Context;
Expand Down Expand Up @@ -34,6 +35,7 @@ use flags::EszipV2ChecksumKind;
use flags::OtelConsoleConfig;
use flags::OtelKind;
use log::warn;
use tokio::time::timeout;

mod env;
mod flags;
Expand Down Expand Up @@ -319,6 +321,10 @@ fn main() -> Result<ExitCode, anyhow::Error> {
} else {
vec![]
};
let timeout_dur = sub_matches
.get_one::<u64>("timeout")
.cloned()
.map(Duration::from_secs);

if import_map_path.is_some() {
warn!(concat!(
Expand Down Expand Up @@ -382,14 +388,24 @@ fn main() -> Result<ExitCode, anyhow::Error> {
emitter_factory.set_deno_options(builder.build()?);

let mut metadata = Metadata::default();
let eszip = generate_binary_eszip(
let eszip_fut = generate_binary_eszip(
&mut metadata,
Arc::new(emitter_factory),
None,
maybe_checksum_kind,
Some(static_patterns),
)
.await?;
);

let eszip = if let Some(dur) = timeout_dur {
match timeout(dur, eszip_fut).await {
Ok(eszip) => eszip,
Err(_) => {
bail!("Failed to complete the bundle within the given time.")
}
}
} else {
eszip_fut.await
}?;

let bin = eszip.into_bytes();

Expand Down
14 changes: 14 additions & 0 deletions crates/base/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Supabase EdgeRuntime base

This crate is part of the Supabase Edge Runtime stack and implements the runtime
core features.

## Architecture

<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="/assets/edge-runtime-diagram-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="/assets/edge-runtime-diagram.svg">
<img alt="Sequence diagram of Edge Runtime request flow" src="/assets/edge-runtime-diagram.svg" style="max-width: 100%;">
</picture>
</p>
43 changes: 15 additions & 28 deletions crates/base/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ use deno_cache::SqliteBackedCache;
use deno_core::error::AnyError;
use deno_core::error::JsError;
use deno_core::serde_json;
use deno_core::serde_json::Value;
use deno_core::url::Url;
use deno_core::v8;
use deno_core::v8::GCCallbackFlags;
Expand All @@ -80,7 +79,6 @@ use deno_facade::EmitterFactory;
use deno_facade::EszipPayloadKind;
use deno_facade::Metadata;
use either::Either;
use ext_event_worker::events::EventMetadata;
use ext_event_worker::events::WorkerEventWithMetadata;
use ext_runtime::cert::ValueRootCertStoreProvider;
use ext_runtime::external_memory::CustomAllocator;
Expand Down Expand Up @@ -462,6 +460,7 @@ where
pub(crate) async fn new(mut worker: Worker) -> Result<Self, Error> {
let init_opts = worker.init_opts.take();
let flags = worker.flags.clone();
let event_metadata = worker.event_metadata.clone();

debug_assert!(init_opts.is_some(), "init_opts must not be None");

Expand Down Expand Up @@ -658,6 +657,10 @@ where
base_url,
} = rt_provider;

let node_modules = metadata
.node_modules()
.ok()
.flatten();
let entrypoint = metadata.entrypoint.clone();
let main_module_url = match entrypoint.as_ref() {
Some(Entrypoint::Key(key)) => base_url.join(key)?,
Expand Down Expand Up @@ -717,6 +720,7 @@ where

let (fs, s3_fs) = build_file_system_fn(if is_user_worker {
Arc::new(StaticFs::new(
node_modules,
static_files,
if matches!(entrypoint, Some(Entrypoint::ModuleCode(_)) | None)
&& is_some_entry_point
Expand Down Expand Up @@ -1106,7 +1110,6 @@ where
s3_fs,
beforeunload_cpu_threshold,
beforeunload_mem_threshold,
context,
..
} = match bootstrap_ret {
Ok(Ok(v)) => v,
Expand All @@ -1118,7 +1121,7 @@ where
}
};

let context = context.unwrap_or_default();
let otel_attributes = event_metadata.otel_attributes.clone();
let span = Span::current();
let post_task_ret = unsafe {
spawn_blocking_non_send(|| {
Expand Down Expand Up @@ -1146,46 +1149,30 @@ where
op_state.put::<HashMap<usize, CancellationToken>>(HashMap::new());
}

let mut otel_attributes = HashMap::new();

otel_attributes.insert(
"edge_runtime.worker.kind".into(),
conf.to_worker_kind().to_string().into(),
);

if conf.is_user_worker() {
let conf = conf.as_user_worker().unwrap();
let key = conf.key.map_or("".to_string(), |k| k.to_string());

// set execution id for user workers
env_vars.insert("SB_EXECUTION_ID".to_string(), key.clone());

if let Some(Value::Object(attributes)) = context.get("otel") {
for (k, v) in attributes {
otel_attributes.insert(
k.to_string().into(),
match v {
Value::String(str) => str.to_string().into(),
others => others.to_string().into(),
},
);
}
}

if let Some(events_msg_tx) = conf.events_msg_tx.clone() {
op_state.put::<mpsc::UnboundedSender<WorkerEventWithMetadata>>(
events_msg_tx,
);
op_state.put::<EventMetadata>(EventMetadata {
service_path: conf.service_path.clone(),
execution_id: conf.key,
});
op_state.put(event_metadata);
}
}

op_state.put(ext_env::EnvVars(env_vars));
op_state.put(DenoRuntimeDropToken(DropToken(drop_token.clone())));
op_state.put(RuntimeOtelExtraAttributes(otel_attributes));
op_state.put(RuntimeOtelExtraAttributes(
otel_attributes
.unwrap_or_default()
.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect(),
));
}

if is_user_worker {
Expand Down
1 change: 1 addition & 0 deletions crates/base/src/utils/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ impl TestBedBuilder {
}
}

#[derive(Clone)]
pub struct TestBed {
pool_termination_token: TerminationToken,
main_termination_token: TerminationToken,
Expand Down
2 changes: 1 addition & 1 deletion crates/base/src/worker/supervisor/strategy_per_worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ pub async fn supervise(args: Arguments) -> (ShutdownReason, i64) {
worker_timeout_ms
};

let wall_clock_duration = Duration::from_millis(worker_timeout_ms);
let wall_clock_duration = Duration::from_millis(wall_clock_limit_ms);

// Split wall clock duration into 2 intervals.
// At the first interval, we will send a msg to retire the worker.
Expand Down
32 changes: 28 additions & 4 deletions crates/base/src/worker/utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use std::collections::HashMap;

use anyhow::anyhow;
use anyhow::bail;
use deno_core::serde_json::Value;
use ext_event_worker::events::EventMetadata;
use ext_event_worker::events::WorkerEventWithMetadata;
use ext_event_worker::events::WorkerEvents;
Expand All @@ -15,18 +18,39 @@ use tokio::sync::oneshot;
use tokio_util::sync::CancellationToken;

pub fn get_event_metadata(conf: &WorkerRuntimeOpts) -> EventMetadata {
let mut otel_attributes = HashMap::new();
let mut event_metadata = EventMetadata {
service_path: None,
execution_id: None,
otel_attributes: None,
};

otel_attributes.insert(
"edge_runtime.worker.kind".to_string(),
conf.to_worker_kind().to_string(),
);

if conf.is_user_worker() {
let conf = conf.as_user_worker().unwrap();
event_metadata = EventMetadata {
service_path: conf.service_path.clone(),
execution_id: conf.key,
};
let context = conf.context.clone().unwrap_or_default();

event_metadata.service_path = conf.service_path.clone();
event_metadata.execution_id = conf.key;

if let Some(Value::Object(attributes)) = context.get("otel") {
for (k, v) in attributes {
otel_attributes.insert(
k.to_string(),
match v {
Value::String(str) => str.to_string(),
others => others.to_string(),
},
);
}
}
}

event_metadata.otel_attributes = Some(otel_attributes);
event_metadata
}

Expand Down
Loading