From 9c877e508ee3e2c9dfd37965a58fbe5eea1af947 Mon Sep 17 00:00:00 2001 From: Lakshan Perera Date: Fri, 10 May 2024 11:48:18 +1000 Subject: [PATCH] feat: expose systemMemoryInfo API for main worker Adding it to EdgeRuntime namespace instead of Deno namespace, to prevent accidentally exposing it in user workers. Also, we are implementing customized version of it for performance reasons (ie. only support Linux via sysinfo) --- crates/sb_core/js/main_worker.js | 7 +++-- crates/sb_os/lib.rs | 54 +++++++++++++++++++++++++++++++- examples/main/index.ts | 13 +++++--- 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/crates/sb_core/js/main_worker.js b/crates/sb_core/js/main_worker.js index afcbc1396..14b77cdce 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 e6974385a..18e0539f9 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 2ac8da077..6c51a74ea 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, }, ); }