From 97ecc6edd6f6137aa6198e12a762ad132051269d Mon Sep 17 00:00:00 2001 From: udo Date: Mon, 13 Jul 2026 12:25:42 +0000 Subject: [PATCH] keep web requests off rebuild path --- docs/wasm-runtime-architecture.md | 13 +++++++------ scripts/test_dependency_invalidation.sh | 20 ++++++++++++++++++++ src/lib/compiler.cpp | 7 +++++++ src/lib/compiler.h | 1 + src/wasm/backend.cpp | 2 +- src/wasm/worker.cpp | 2 +- 6 files changed, 37 insertions(+), 8 deletions(-) diff --git a/docs/wasm-runtime-architecture.md b/docs/wasm-runtime-architecture.md index 5844e68..071c2aa 100644 --- a/docs/wasm-runtime-architecture.md +++ b/docs/wasm-runtime-architecture.md @@ -138,12 +138,13 @@ following allocator/relocation call even though no guest loop consumed it. The proactive compiler and request workers coordinate through a per-unit file lock. Unit compilation writes and validates a process-unique temporary wasm -file, then publishes it with an atomic rename. While another process holds the -lock for a stale unit, a request may therefore keep using the last complete -artifact instead of waiting across a transitive rebuild. Once the lock is -released, normal freshness checks require the new artifact; a failed rebuild -removes availability and surfaces the compiler error rather than serving the -old unit indefinitely. +file, then publishes it with an atomic rename. When proactive compilation is +enabled, HTTP and WebSocket requests keep using the last complete artifact +while stale units rebuild in the background; CLI and explicit compile paths +remain synchronous. A failed rebuild removes availability and surfaces the +compiler error rather than serving the old unit indefinitely. The per-unit lock +also keeps concurrent synchronous compilers from waiting across a transitive +graph when a last complete artifact is available. --- diff --git a/scripts/test_dependency_invalidation.sh b/scripts/test_dependency_invalidation.sh index afe2704..70c5088 100755 --- a/scripts/test_dependency_invalidation.sh +++ b/scripts/test_dependency_invalidation.sh @@ -11,6 +11,7 @@ if [[ -z "$bin_directory" && -r /etc/uce/settings.cfg ]]; then fi bin_directory="${bin_directory:-/tmp/uce/work}" cache_dir="" +http_host="${UCE_TEST_HTTP_HOST:-uce.openfu.com}" cleanup() { rm -rf "$source_dir" @@ -43,9 +44,28 @@ assert_marker() { fi } +http_marker() { + curl -fsS -H "Host: $http_host" "http://127.0.0.1/$test_name/parent.uce" +} + assert_marker parent dependency-marker-a +if [[ "$(http_marker)" != *"dependency-marker-a"* ]]; then + echo "HTTP warm-up did not return dependency-marker-a" >&2 + exit 1 +fi sed -i 's/dependency-marker-a/dependency-marker-b/' "$source_dir/child.uce" +started_at=$(date +%s%N) +http_during_rebuild=$(http_marker) +elapsed_ms=$(( ($(date +%s%N) - started_at) / 1000000 )) +if [[ "$http_during_rebuild" != *"dependency-marker-a"* && "$http_during_rebuild" != *"dependency-marker-b"* ]]; then + echo "HTTP rebuild request returned neither complete artifact: $http_during_rebuild" >&2 + exit 1 +fi +if (( elapsed_ms >= 2000 )); then + echo "HTTP request spent ${elapsed_ms}ms rebuilding a stale artifact" >&2 + exit 1 +fi assert_marker parent dependency-marker-b # A proactive rebuild owns these same per-unit locks. While it publishes fresh diff --git a/src/lib/compiler.cpp b/src/lib/compiler.cpp index e4bb23a..441c45c 100644 --- a/src/lib/compiler.cpp +++ b/src/lib/compiler.cpp @@ -975,6 +975,13 @@ bool compiler_unit_compile_in_progress(Request* context, String file_name) return(false); } +bool compiler_request_can_serve_stale_artifact(Request* context) +{ + return(context && context->server && !context->resources.is_cli && + to_bool(context->server->config["PROACTIVE_COMPILE_ENABLED"], true) && + float_val(context->server->config["PROACTIVE_COMPILE_CHECK_INTERVAL"]) > 0); +} + void unit_render(String file_name) { unit_render(file_name, *context); diff --git a/src/lib/compiler.h b/src/lib/compiler.h index ad88f1a..bc32b05 100644 --- a/src/lib/compiler.h +++ b/src/lib/compiler.h @@ -18,6 +18,7 @@ SharedUnit* get_shared_unit(Request* context, String file_name); String compiler_error_page_unit(Request* context, String config_key); bool compiler_unit_compile_pending(Request* context, String file_name); bool compiler_unit_compile_in_progress(Request* context, String file_name); +bool compiler_request_can_serve_stale_artifact(Request* context); String compiler_site_directory(Request* context); StringList compiler_scan_site_units(Request* context); StringList compiler_list_known_units(Request* context); diff --git a/src/wasm/backend.cpp b/src/wasm/backend.cpp index f22d349..3bb6c3d 100644 --- a/src/wasm/backend.cpp +++ b/src/wasm/backend.cpp @@ -100,7 +100,7 @@ static bool wasm_artifact_exists(Request* context, const String& entry_unit) // metadata mismatches, which can leave stale wasm with old imports. bool source_missing = false; if(compiler_unit_needs_recompile(context, entry_unit, &source_missing)) - return(compiler_unit_compile_in_progress(context, entry_unit)); + return(compiler_request_can_serve_stale_artifact(context) || compiler_unit_compile_in_progress(context, entry_unit)); if(source_missing) return(false); return(true); diff --git a/src/wasm/worker.cpp b/src/wasm/worker.cpp index 3489fec..fcb3366 100644 --- a/src/wasm/worker.cpp +++ b/src/wasm/worker.cpp @@ -1606,7 +1606,7 @@ private: return(1); } - if(!file_exists_host(worker.unit_wasm_path(resolved)) || (compiler_unit_needs_recompile(context, resolved, 0) && !compiler_unit_compile_in_progress(context, resolved))) + if(!file_exists_host(worker.unit_wasm_path(resolved)) || (compiler_unit_needs_recompile(context, resolved, 0) && !compiler_request_can_serve_stale_artifact(context) && !compiler_unit_compile_in_progress(context, resolved))) get_shared_unit(context, resolved); size_t unit_index = 0;