fix: prevent stale mutation execution

This commit is contained in:
udo
2026-07-13 20:17:48 +00:00
parent 0187bb60cf
commit 92baaa6299
7 changed files with 140 additions and 15 deletions
+57
View File
@@ -312,6 +312,11 @@ String compiler_registry_lock_file_name(Request* context)
return(compiler_registry_file_name(context) + ".lock");
}
String compiler_priority_file_name(Request* context)
{
return(context->server->config["BIN_DIRECTORY"] + "/proactive-priority.txt");
}
int compiler_open_lock_file(String file_name, String purpose, bool nonblocking = false)
{
(void)purpose;
@@ -1015,6 +1020,58 @@ bool compiler_request_can_serve_stale_artifact(Request* context)
float_val(context->server->config["PROACTIVE_COMPILE_CHECK_INTERVAL"]) > 0);
}
void compiler_prioritize_unit(Request* context, String file_name)
{
if(!compiler_request_can_serve_stale_artifact(context))
return;
file_name = compiler_normalize_unit_path(context, file_name);
if(file_name == "" || file_name.find('\n') != String::npos || file_name.find('\r') != String::npos)
return;
String queue_file = compiler_priority_file_name(context);
int fd = compiler_open_lock_file(queue_file + ".lock", "proactive-priority");
if(fd < 0)
return;
int queue_fd = open(queue_file.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);
if(queue_fd >= 0)
{
String line = file_name + "\n";
ssize_t offset = 0;
while(offset < (ssize_t)line.size())
{
ssize_t written = write(queue_fd, line.data() + offset, line.size() - offset);
if(written <= 0)
break;
offset += written;
}
close(queue_fd);
}
compiler_close_lock_file(fd);
}
StringList compiler_take_priority_units(Request* context)
{
StringList result;
if(!context || !context->server)
return(result);
String queue_file = compiler_priority_file_name(context);
int fd = compiler_open_lock_file(queue_file + ".lock", "proactive-priority");
if(fd < 0)
return(result);
if(file_exists(queue_file))
{
for(auto file_name : split(file_get_contents(queue_file), "\n"))
{
file_name = trim(file_name);
if(file_name != "" && std::find(result.begin(), result.end(), file_name) == result.end())
result.push_back(file_name);
}
file_put_contents(queue_file, "");
}
compiler_close_lock_file(fd);
return(result);
}
void unit_render(String file_name)
{
unit_render(file_name, *context);
+2
View File
@@ -19,6 +19,8 @@ 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);
void compiler_prioritize_unit(Request* context, String file_name);
StringList compiler_take_priority_units(Request* context);
String compiler_site_directory(Request* context);
StringList compiler_scan_site_units(Request* context);
StringList compiler_list_known_units(Request* context);
+23 -2
View File
@@ -575,6 +575,17 @@ int handle_complete(FastCGIRequest& request) {
};
String entry_unit = compiler_normalize_unit_path(&request, request.params["SCRIPT_FILENAME"]);
String request_method = to_upper(trim(request.params["REQUEST_METHOD"]));
bool read_request = request_method == "GET" || request_method == "HEAD" || request_method == "OPTIONS";
bool stale_mutation = !request.resources.is_cli && !read_request && compiler_unit_needs_recompile(&request, entry_unit);
if(stale_mutation)
{
compiler_prioritize_unit(&request, entry_unit);
request.set_status(503, "Service Unavailable");
request.header["Content-Type"] = "text/plain; charset=utf-8";
request.header["Retry-After"] = "1";
print("The requested code is being updated. Retry this request shortly.\n");
}
// W7e: every unit runs on wasm. When the artifact is missing or stale
// (cold worker, or source edited since the last compile), compile the
// unit on demand — get_shared_unit() builds the .wasm side-module — and
@@ -593,7 +604,11 @@ int handle_complete(FastCGIRequest& request) {
failure_trace = "source: " + request.params["SCRIPT_FILENAME"];
};
if(request.params["UCE_WS"] == "1")
if(stale_mutation)
{
// The response above deliberately bypasses all stale application code.
}
else if(request.params["UCE_WS"] == "1")
{
// A WS message the broker forwarded here: rebuild the connection
// context the broker passed as params, then run __uce_websocket.
@@ -1243,7 +1258,13 @@ void run_proactive_compiler()
{
try
{
if(compile_queue.size() == 0 && time_precise() >= next_scan_at)
auto priority_units = compiler_take_priority_units(&background_context);
for(auto it = priority_units.rbegin(); it != priority_units.rend(); ++it)
{
compile_queue.erase(std::remove(compile_queue.begin(), compile_queue.end(), *it), compile_queue.end());
compile_queue.insert(compile_queue.begin(), *it);
}
if(compile_queue.size() == 0 && time_precise() >= next_scan_at)
{
auto tracked_units = compiler_list_known_units(&background_context);
StringList existing_units;
+3
View File
@@ -100,7 +100,10 @@ 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))
{
compiler_prioritize_unit(context, entry_unit);
return(compiler_request_can_serve_stale_artifact(context));
}
if(source_missing)
return(false);
return(true);
+4 -1
View File
@@ -1606,7 +1606,10 @@ private:
return(1);
}
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)))
bool stale = compiler_unit_needs_recompile(context, resolved, 0);
if(stale && compiler_request_can_serve_stale_artifact(context))
compiler_prioritize_unit(context, resolved);
if(!file_exists_host(worker.unit_wasm_path(resolved)) || (stale && !compiler_request_can_serve_stale_artifact(context) && !compiler_unit_compile_in_progress(context, resolved)))
get_shared_unit(context, resolved);
size_t unit_index = 0;