feat: extend wasm backend entrypoints
This commit is contained in:
+40
-6
@@ -151,13 +151,13 @@ static bool wasm_backend_native_fallback_needed(Request* context, const String&
|
||||
|
||||
// True if this request should be served by the wasm backend. Falls through to
|
||||
// native when disabled, when init failed, or when the unit has no wasm artifact
|
||||
// (e.g. units skip-listed for try/catch — automatic, graceful fallback).
|
||||
// (e.g. units skip-listed for try/catch — automatic, graceful fallback). Mode-
|
||||
// agnostic: the caller (page render / cli / serve_http) decides which entry to
|
||||
// route here; this only gates on config, fallback tokens, artifact, and worker.
|
||||
bool wasm_backend_should_handle(Request& request, const String& entry_unit)
|
||||
{
|
||||
if(!wasm_backend_configured(&request))
|
||||
return(false);
|
||||
if(request.resources.is_cli)
|
||||
return(false);
|
||||
if(wasm_backend_native_fallback_needed(&request, entry_unit))
|
||||
return(false);
|
||||
if(!wasm_artifact_exists(&request, entry_unit))
|
||||
@@ -167,11 +167,13 @@ bool wasm_backend_should_handle(Request& request, const String& entry_unit)
|
||||
return(true);
|
||||
}
|
||||
|
||||
// Serve the page render through a wasm workspace. Populates the native Request
|
||||
// Serve a request through a wasm workspace using the unit handler selected by
|
||||
// `kind` (page render / cli / serve_http). Populates the native Request
|
||||
// (status/headers/cookies/session/body) so the existing transport writes the
|
||||
// response unchanged. Returns "" on success, or a collapsed error/trace string
|
||||
// for the caller to route into the configured error page.
|
||||
String wasm_backend_serve(Request& request, const String& entry_unit)
|
||||
String wasm_backend_serve(Request& request, const String& entry_unit, int32_t kind = WasmWorkspace::RESOLVE_RENDER,
|
||||
const String& handler_name = "")
|
||||
{
|
||||
DValue ctx;
|
||||
auto copy_map = [&](const StringMap& source, const char* key) {
|
||||
@@ -184,11 +186,24 @@ String wasm_backend_serve(Request& request, const String& entry_unit)
|
||||
copy_map(request.cookies, "cookies");
|
||||
copy_map(request.session, "session");
|
||||
ctx["entry_unit"] = entry_unit;
|
||||
// Raw request body: cli_input() parses a JSON CLI payload from context.in,
|
||||
// and ws_message() exposes the websocket frame from it — both need it carried
|
||||
// into the workspace, not just the form-decoded post map.
|
||||
ctx["in"] = request.in;
|
||||
|
||||
WasmResponse response = wasm_worker_serve(*g_wasm_worker, ctx, entry_unit);
|
||||
WasmResponse response = wasm_worker_serve(*g_wasm_worker, ctx, entry_unit, kind, handler_name);
|
||||
if(!response.ok)
|
||||
return(response.error == "" ? String("wasm workspace failed") : response.error);
|
||||
|
||||
// A cli/serve_http unit that does not export the requested handler is a 404,
|
||||
// matching native compiler_invoke_cli ("CLI Entry Point Not Found"). For page
|
||||
// render a missing handler is simply an empty body (native parity).
|
||||
if(!response.handler_present && kind != WasmWorkspace::RESOLVE_RENDER)
|
||||
{
|
||||
request.set_status(404, kind == WasmWorkspace::RESOLVE_CLI ? "CLI Entry Point Not Found" : "Handler Not Found");
|
||||
return("");
|
||||
}
|
||||
|
||||
// Diagnostic timing headers are opt-in: they leak workspace internals and
|
||||
// belong to the W5 benchmark harness, not public responses.
|
||||
if(config_bool("WASM_BACKEND_VERBOSE", false))
|
||||
@@ -237,3 +252,22 @@ void wasm_backend_shutdown()
|
||||
if(g_wasm_epoch_running.exchange(false) && g_wasm_epoch_ticker.joinable())
|
||||
g_wasm_epoch_ticker.join();
|
||||
}
|
||||
|
||||
// A connection-broker child (the custom-server HTTP dispatcher, the websocket
|
||||
// exec child) is forked from a worker that may already have brought up its wasm
|
||||
// engine. The Wasmtime engine and the epoch-ticker thread must not cross fork:
|
||||
// the child inherits the pointer/flags but only the forking thread survives, so
|
||||
// the ticker is a phantom and the engine state is unsafe. Reset the per-process
|
||||
// statics so the child lazily initializes its own engine + ticker on first use.
|
||||
// The inherited std::thread refers to a thread that does not exist in the child;
|
||||
// placement-new it back to a default (non-joinable) state so the eventual
|
||||
// re-assignment in ensure_started does not std::terminate on a "joinable" object,
|
||||
// and so no join/detach touches the dead handle.
|
||||
void wasm_backend_reset_after_fork()
|
||||
{
|
||||
g_wasm_worker = 0;
|
||||
g_wasm_init_attempted = false;
|
||||
g_wasm_init_error = "";
|
||||
g_wasm_epoch_running.store(false);
|
||||
new (&g_wasm_epoch_ticker) std::thread();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user