fix: reconcile prunes by GitHub PR state, not KV — runs on the preview nodes as-is (v0.3.0) [review, do not merge yet] - #38
Merged
Conversation
v0.2.0's reconcile read desired state from the KV index over RESP. The preview nodes keep ePHPm's KV RESP listener off (no [kv.redis_compat] listener, no [kv] secret), so that reader was inert there — it could never read desired state and every pass aborted. Switch the prune authority to GitHub PR state, which needs no ePHPm-side change and is more authoritative than the KV index (which has an acknowledged lost-update window). Each pass: - lists every preview directory under sites_dir; - parses its canonical site key <owner>-<repo>-pr-<N> back to (repo, N); - asks GitHub what that PR is now, under the switchboard App creds the daemon already mints reporting tokens with (org installation token, minted once per pass); - open (or an unrecognised state) => keep; merged or closed => prune, via the existing KEEP-guarded, exact-path teardown::teardown_preview. Prune-only by design: re-deploying a missing but still-open preview stays on the webhook path. Fail-safe in every direction — uncertainty always keeps: - a site key that does not parse as <owner>-<repo>-pr-<N> (an infra vhost, or a hashed/overflow PreviewLabel) is skipped, never a candidate; - a per-PR GitHub read error keeps that preview; - a failure to mint the installation token aborts the whole pass, so a total GitHub outage prunes nothing; - the keep-list still applies (the API vhost site key is auto-added). Removes the RESP ClusterReader path and the add-direction plumbing (Queue::enqueue/has_job_for_label) added in #37, so there is one authority. Knobs: --reconcile-interval-secs, --reconcile-prune, --reconcile-keep-sites (all default-off/empty), plus --reconcile-owner (default "ephpm"). Requires --app-id/--app-key when enabled (validated). No ePHPm-side, [kv], or restart change is needed. Tests: merged/closed -> prune, open/unknown -> keep, API-error -> keep, missing-lookup -> keep, unparseable/hashed key -> keep, hyphenated-repo parsing, keep-list respected, dry-run removes nothing, real prune removes.
|
ePHPm Preview — removed Preview deployment has been torn down. |
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
v0.2.0's reconcile (#37) read desired state from the KV index over RESP. On the live preview nodes there is no
[kv.redis_compat]listener and no[kv]secret (127.0.0.1:6379is refused), so that reader was inert — every pass aborted "KV unreadable", pruning nothing. Confirmed on node-2 during the v0.2.0 canary.What changed
Prune authority is now GitHub PR state — needs no ePHPm-side change, and is more authoritative than the KV index (which has an acknowledged lost-update window). Each pass:
sites_dir;<owner>-<repo>-pr-<N>→(repo, N)(parse_preview_site_key; owner from--reconcile-owner, defaultephpm);installation_token_for_owner— reuses the App-JWT pathgithub.rs/main.rsalready use,SWITCHBOARD_APP_ID/--app-key) and asks GitHub what each PR is now;teardown::teardown_preview(site dir,<key>.db*,<key>.toml,/tmp/ephpm-vhosts/<key>-<hash>, preserving*.single-db-bak).Prune-only — re-deploying a missing but still-open preview stays on the existing webhook path (noted in the module docs).
Fail-safe (uncertainty always keeps)
<owner>-<repo>-pr-<N>— an infra vhost (switchboard,site-a, apex) or a hashed/overflowPreviewLabel— is skipped, never a candidate;--reconcile-keep-sites; the API vhost site key auto-added).Removed / simplified
ClusterReader/parse_indexpath from fix: level-triggered reconcile so previews converge across the cluster [DO NOT MERGE — review] #37 (kv.rs) — one authority now;Queue::enqueue/has_job_for_label) — prune-only;--reconcile-deploy-missing,--reconcile-max-prunes-per-cycle,--reconcile-api-site. Kept:--reconcile-interval-secs,--reconcile-prune,--reconcile-keep-sites(all default-off/empty); added--reconcile-owner(defaultephpm).validate()now requires--app-id/--app-keywhen the reconcile is enabled (no silent no-op).Confirmed: NO ePHPm-side /
[kv]/ restart changeThe daemon queries GitHub directly with the App credentials it already has. No
[kv]secret, no[kv.redis_compat]listener, no ePHPm restart. Deploying is a binary swap + a--reconcile-*drop-in.Tests (all green locally)
reconcile.rs:merged_and_closed_prune_open_and_unknown_keep,an_api_error_keeps_the_preview,a_missing_lookup_keeps_the_preview,an_unparseable_key_is_never_a_candidate_even_if_a_lookup_exists,parses_clean_preview_keys_including_hyphenated_repos(php-sdk, switchboard-api, ephpm-ephpm, repo-containing--pr-),refuses_non_preview_and_hashed_keys,label_reconstruction_without_a_suffix_strips_the_domain,list_preview_dirs_filters_infra_staging_and_files,keep_list_excludes_a_dir_from_candidacy,dry_run_reports_would_prune_and_removes_nothing,prune_removes_the_orphan_directory,a_missing_sites_dir_is_an_empty_list.Gates:
cargo check --all-targets,cargo clippy --all-targets -- -D warnings,cargo test(321 passed),cargo fmt --all -- --check,cargo +1.85 check --all-targets(MSRV). Version bumped to 0.3.0 (not tagged — cut the release after merge).