diff --git a/crates/sb_core/js/main_worker.js b/crates/sb_core/js/main_worker.js index afcbc139..14b77cdc 100644 --- a/crates/sb_core/js/main_worker.js +++ b/crates/sb_core/js/main_worker.js @@ -1,6 +1,6 @@ -import { SUPABASE_USER_WORKERS } from "ext:sb_user_workers/user_workers.js"; -import { applySupabaseTag } from "ext:sb_core_main_js/js/http.js"; -import { core } from "ext:core/mod.js"; +import { SUPABASE_USER_WORKERS } from 'ext:sb_user_workers/user_workers.js'; +import { applySupabaseTag } from 'ext:sb_core_main_js/js/http.js'; +import { core } from 'ext:core/mod.js'; const ops = core.ops; @@ -10,6 +10,7 @@ Object.defineProperty(globalThis, 'EdgeRuntime', { userWorkers: SUPABASE_USER_WORKERS, getRuntimeMetrics: () => /* async */ ops.op_runtime_metrics(), applySupabaseTag: (src, dest) => applySupabaseTag(src, dest), + systemMemoryInfo: () => ops.op_system_memory_info(), }; }, configurable: true, diff --git a/crates/sb_os/lib.rs b/crates/sb_os/lib.rs index e6974385..18e0539f 100644 --- a/crates/sb_os/lib.rs +++ b/crates/sb_os/lib.rs @@ -1,5 +1,57 @@ +use deno_core::op2; use std::collections::HashMap; pub type EnvVars = HashMap; -deno_core::extension!(sb_os, esm_entry_point = "ext:sb_os/os.js", esm = ["os.js"]); +#[derive(serde::Serialize)] +#[serde(rename_all = "camelCase")] +pub struct MemInfo { + pub total: u64, + pub free: u64, + pub available: u64, + pub buffers: u64, + pub cached: u64, + pub swap_total: u64, + pub swap_free: u64, +} + +#[op2] +#[serde] +fn op_system_memory_info() -> Option { + let mut mem_info = MemInfo { + total: 0, + free: 0, + available: 0, + buffers: 0, + cached: 0, + swap_total: 0, + swap_free: 0, + }; + + #[cfg(any(target_os = "android", target_os = "linux"))] + { + let mut info = std::mem::MaybeUninit::uninit(); + // SAFETY: `info` is a valid pointer to a `libc::sysinfo` struct. + let res = unsafe { libc::sysinfo(info.as_mut_ptr()) }; + if res == 0 { + // SAFETY: `sysinfo` initializes the struct. + let info = unsafe { info.assume_init() }; + let mem_unit = info.mem_unit as u64; + mem_info.swap_total = info.totalswap * mem_unit; + mem_info.swap_free = info.freeswap * mem_unit; + mem_info.total = info.totalram * mem_unit; + mem_info.free = info.freeram * mem_unit; + mem_info.available = mem_info.free; + mem_info.buffers = info.bufferram * mem_unit; + } + } + + Some(mem_info) +} + +deno_core::extension!( + sb_os, + ops = [op_system_memory_info], + esm_entry_point = "ext:sb_os/os.js", + esm = ["os.js"] +); diff --git a/examples/main/index.ts b/examples/main/index.ts index 2ac8da07..6c51a74e 100644 --- a/examples/main/index.ts +++ b/examples/main/index.ts @@ -1,11 +1,14 @@ // @ts-ignore -import { STATUS_CODE } from "https://deno.land/std/http/status.ts"; +import { STATUS_CODE } from 'https://deno.land/std/http/status.ts'; console.log('main function started'); +// log system memory usage every 30s +// setInterval(() => console.log(EdgeRuntime.systemMemoryInfo()), 30 * 1000); + Deno.serve(async (req: Request) => { const headers = new Headers({ - "Content-Type": "application/json" + 'Content-Type': 'application/json', }); const url = new URL(req.url); @@ -17,7 +20,7 @@ Deno.serve(async (req: Request) => { JSON.stringify({ 'message': 'ok' }), { status: STATUS_CODE.OK, - headers + headers, }, ); } @@ -128,7 +131,7 @@ Deno.serve(async (req: Request) => { console.error(e); if (e instanceof Deno.errors.WorkerRequestCancelled) { - headers.append("Connection", "close"); + headers.append('Connection', 'close'); // XXX(Nyannyacha): I can't think right now how to re-poll // inside the worker pool without exposing the error to the @@ -150,7 +153,7 @@ Deno.serve(async (req: Request) => { JSON.stringify(error), { status: STATUS_CODE.InternalServerError, - headers + headers, }, ); }