Prioritize stale dynamic components
This commit is contained in:
+51
-5
@@ -1117,6 +1117,12 @@ public:
|
||||
|
||||
private:
|
||||
friend class WasmWorkspace;
|
||||
struct ComponentFreshnessState
|
||||
{
|
||||
std::chrono::steady_clock::time_point checked_at;
|
||||
bool stale = false;
|
||||
};
|
||||
std::map<String, ComponentFreshnessState> component_freshness;
|
||||
|
||||
static String cached_wasm_path(const String& wasm_path)
|
||||
{
|
||||
@@ -1491,6 +1497,13 @@ public:
|
||||
String decode_error;
|
||||
if(!ucb_decode(meta_encoded, response.meta, &decode_error))
|
||||
return("response meta decode failed: " + decode_error);
|
||||
if(stale_component_mutation_blocked)
|
||||
{
|
||||
response.body = "The requested code is being updated. Retry this request shortly.\n";
|
||||
response.meta["status"] = stale_component_mutation_status;
|
||||
response.meta["headers"]["Content-Type"] = "text/plain; charset=utf-8";
|
||||
response.meta["headers"]["Retry-After"] = "1";
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
@@ -1513,6 +1526,8 @@ private:
|
||||
std::map<String, size_t> units_by_source;
|
||||
std::map<String, u32> handler_slots; // source + ":" + symbol → table slot
|
||||
std::vector<wasmtime::Func> host_funcs; // keep host imports alive
|
||||
bool stale_component_mutation_blocked = false;
|
||||
String stale_component_mutation_status;
|
||||
|
||||
wasmtime::Store::Context ctx()
|
||||
{
|
||||
@@ -2180,11 +2195,42 @@ private:
|
||||
auto artifact_start = std::chrono::steady_clock::now();
|
||||
bool artifact_exists = file_exists_host(worker.unit_wasm_path(resolved));
|
||||
bool can_serve_stale = compiler_request_can_serve_stale_artifact(context);
|
||||
// The proactive compiler owns freshness while stale HTTP artifacts may be
|
||||
// served. Keep source-graph scans off that request path; CLI/non-stale
|
||||
// execution still checks synchronously and cold artifacts still compile.
|
||||
bool stale = !can_serve_stale && artifact_exists && compiler_unit_needs_recompile(context, resolved, 0);
|
||||
if(!artifact_exists || stale)
|
||||
String method = context ? to_upper(trim(context->params["REQUEST_METHOD"])) : String("");
|
||||
bool read_request = method == "GET" || method == "HEAD" || method == "OPTIONS";
|
||||
bool stale = false;
|
||||
if(artifact_exists)
|
||||
{
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
auto cached_freshness = worker.component_freshness.find(resolved);
|
||||
// HTTP reads may serve a complete stale artifact, so bound their graph
|
||||
// stat work; CLI and mutations always check the current graph.
|
||||
bool check_freshness = !can_serve_stale || !read_request ||
|
||||
cached_freshness == worker.component_freshness.end() ||
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
now - cached_freshness->second.checked_at).count() >= 1000;
|
||||
if(check_freshness)
|
||||
{
|
||||
stale = compiler_unit_needs_recompile(context, resolved, 0);
|
||||
worker.component_freshness[resolved] = { now, stale };
|
||||
}
|
||||
else
|
||||
stale = cached_freshness->second.stale;
|
||||
}
|
||||
if(stale && can_serve_stale)
|
||||
{
|
||||
compiler_prioritize_unit(context, resolved);
|
||||
if(!read_request)
|
||||
{
|
||||
stale_component_mutation_blocked = true;
|
||||
stale_component_mutation_status = context->params["GATEWAY_INTERFACE"] != "" ?
|
||||
"Status: 503 Service Unavailable" : "HTTP/1.1 503 Service Unavailable";
|
||||
component_artifact_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::steady_clock::now() - artifact_start).count();
|
||||
record_probe();
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
if(!artifact_exists || (stale && !can_serve_stale))
|
||||
get_shared_unit(context, resolved);
|
||||
component_artifact_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::steady_clock::now() - artifact_start).count();
|
||||
|
||||
Reference in New Issue
Block a user