Prioritize stale dynamic components
This commit is contained in:
@@ -18,6 +18,10 @@ fi
|
||||
bin_directory="${bin_directory:-/tmp/uce/work}"
|
||||
cache_dir=""
|
||||
mutation_file="/tmp/uce-dependency-mutation-$$"
|
||||
component_mutation_file="/tmp/uce-component-mutation-$$"
|
||||
component_post_body="/tmp/uce-component-post-body-$$"
|
||||
component_post_headers="/tmp/uce-component-post-headers-$$"
|
||||
component_lock_ready_file="/tmp/uce-component-lock-ready-$$"
|
||||
post_body="/tmp/uce-dependency-post-body-$$"
|
||||
post_headers="/tmp/uce-dependency-post-headers-$$"
|
||||
lock_ready_file="/tmp/uce-dependency-lock-ready-$$"
|
||||
@@ -32,7 +36,7 @@ cleanup() {
|
||||
if [[ -n "$cache_dir" ]]; then
|
||||
rm -rf "$cache_dir"
|
||||
fi
|
||||
rm -f "$mutation_file" "$post_body" "$post_headers" "$lock_ready_file" "$nested_lock_ready_file" "$race_output" "$race_error" "$race_status"
|
||||
rm -f "$mutation_file" "$component_mutation_file" "$component_post_body" "$component_post_headers" "$component_lock_ready_file" "$post_body" "$post_headers" "$lock_ready_file" "$nested_lock_ready_file" "$race_output" "$race_error" "$race_status"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
mkdir -p "$source_dir"
|
||||
@@ -69,6 +73,80 @@ if [[ "$(http_marker)" != *"dependency-marker-a"* ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# HTTP entry units can resolve route/components dynamically. A changed dynamic
|
||||
# component must enter the demand-priority queue just like a changed entry unit;
|
||||
# otherwise a common dependency rebuild can leave the requested page stale for
|
||||
# the duration of the full proactive queue.
|
||||
printf '%s\n' "COMPONENT(Request& context) { if(context.params[\"REQUEST_METHOD\"] == \"POST\") file_put_contents(\"$component_mutation_file\", \"executed\"); print(\"http-component-marker-a\"); }" >"$source_dir/http-component-child.uce"
|
||||
printf '%s\n' 'RENDER(Request& context) { DValue props; print(component("http-component-child", props, context)); }' >"$source_dir/http-component-parent.uce"
|
||||
http_component_marker() {
|
||||
curl -fsS -H "Host: $http_host" "http://127.0.0.1/$test_name/http-component-parent.uce"
|
||||
}
|
||||
if [[ "$(http_component_marker)" != *"http-component-marker-a"* ]]; then
|
||||
echo "HTTP component warm-up did not return marker-a" >&2
|
||||
exit 1
|
||||
fi
|
||||
sed -i 's/http-component-marker-a/http-component-marker-b/' "$source_dir/http-component-child.uce"
|
||||
started_at=$(date +%s%N)
|
||||
http_component_output=$(http_component_marker)
|
||||
elapsed_ms=$(( ($(date +%s%N) - started_at) / 1000000 ))
|
||||
if [[ "$http_component_output" != *"http-component-marker-a"* && "$http_component_output" != *"http-component-marker-b"* ]]; then
|
||||
echo "stale HTTP component request returned neither complete artifact: $http_component_output" >&2
|
||||
exit 1
|
||||
fi
|
||||
if (( elapsed_ms >= 2000 )); then
|
||||
echo "HTTP component request spent ${elapsed_ms}ms rebuilding a stale artifact" >&2
|
||||
exit 1
|
||||
fi
|
||||
deadline=$((SECONDS + 15))
|
||||
while [[ "$http_component_output" != *"http-component-marker-b"* && $SECONDS -lt $deadline ]]; do
|
||||
sleep 0.2
|
||||
http_component_output=$(http_component_marker)
|
||||
done
|
||||
if [[ "$http_component_output" != *"http-component-marker-b"* ]]; then
|
||||
echo "requested stale HTTP component did not receive a demand-priority rebuild" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Mutations must never execute a stale dynamically resolved component, even
|
||||
# inside the short read-only freshness memo window.
|
||||
http_component_wasm="$cache_dir/http-component-child.uce.wasm"
|
||||
(
|
||||
exec 8>"$http_component_wasm.lock"
|
||||
flock 8
|
||||
: >"$component_lock_ready_file"
|
||||
sleep 2
|
||||
) &
|
||||
component_lock_pid=$!
|
||||
deadline=$((SECONDS + 5))
|
||||
while [[ ! -e "$component_lock_ready_file" && $SECONDS -lt $deadline ]]; do sleep 0.05; done
|
||||
if [[ ! -e "$component_lock_ready_file" ]]; then
|
||||
echo "HTTP component mutation lock was not acquired before deadline" >&2
|
||||
exit 1
|
||||
fi
|
||||
sed -i 's/http-component-marker-b/http-component-marker-c/' "$source_dir/http-component-child.uce"
|
||||
rm -f "$component_mutation_file"
|
||||
component_post_status=$(curl -sS -o "$component_post_body" -D "$component_post_headers" -w '%{http_code}' -X POST -H "Host: $http_host" "http://127.0.0.1/$test_name/http-component-parent.uce")
|
||||
if [[ "$component_post_status" != "503" ]]; then
|
||||
echo "stale HTTP component mutation did not fail closed: status=$component_post_status body=$(cat "$component_post_body")" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! grep -qi '^Retry-After: 1' "$component_post_headers"; then
|
||||
echo "stale HTTP component mutation omitted Retry-After" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ -e "$component_mutation_file" ]]; then
|
||||
echo "stale HTTP component mutation executed application code" >&2
|
||||
exit 1
|
||||
fi
|
||||
wait "$component_lock_pid"
|
||||
deadline=$((SECONDS + 15))
|
||||
while [[ "$(http_component_marker)" != *"http-component-marker-c"* && $SECONDS -lt $deadline ]]; do sleep 0.2; done
|
||||
if [[ "$(http_component_marker)" != *"http-component-marker-c"* ]]; then
|
||||
echo "HTTP component did not recover after the guarded mutation rebuild" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# A failed parent build must remember the exact dependency graph that failed.
|
||||
# If a dependency is restored byte-for-byte to the last working source, the
|
||||
# old successful metadata must not make that transient failure permanent.
|
||||
|
||||
Reference in New Issue
Block a user