chadtmiller.com/knotless
git that lives in your Atmosphere account
Private repository pages no longer wait on the sync a change started
MergedThis moves private-repository syncs into the background. Each change starts one task per mirror whose viewer was proven within the minute. A page's reads are served viewed_last while that sync runs. A read that carries a delegation token, or that follows a write from the pages, still waits. The design reads soundly to me: catching dedupes per mirror, forget and unview clear viewed_last, and serving still requires a recent proof and a followed space.
The pull does not compile, though. Clippy and the e2e build both fail with E0592: duplicate definitions with name resync. The new App::resync in private.rs collides with the existing async fn resync(&self, index, org) in orgs.rs:193, which is also an impl App method. Rename the new one, for example to resync_viewed. This is what the failing check and e2e runs already report. I did not see test finish, so the new second-push test is still unverified.
crates/knotless-serve/src/private.rsline 288Outdated
| |
/// Syncs `entry`, `did`'s private repository `url`, from `remote` read | |
/// with `ctx`, and notes what it is then fresh as of. | |
async fn resync( |
App::resync is already defined in orgs.rs:193 (E0592), so this does not compile. Rename it, e.g. resync_viewed, and update the two callers (as_viewer and caught_up).
The rename I asked for is done. App::resync in private.rs is now sync_viewed, and both callers (as_viewer and the background caught_up path) use it, so the E0592 collision with orgs.rs is gone. Nothing else changed since my last review, and I still find the design sound.
I could not confirm the build. When I looked, the check, e2e and test runs were still going at this head. test includes the new second-push case in private_repositories_indexed_here. A failure in those runs is for the checks to report, so I'm not withholding approval for it.
My approval at 902cc83 stands. Since then the pull changes one thing: viewed_served is now async and awaits keep(space, viewer) before serving the stale mirror. That matches the description, which says a served read still makes its reader the space's syncer. The OptionFuture wrapper in lib.rs keeps the call lazy, so it runs only when aside is set. If keep fails, the read falls through to the normal path rather than serving stale, which is the safe direction.
check (fmt and clippy) passed at this head. test and e2e were still running when I looked. I'm not withholding approval for them, since the checks report failures themselves.
My approval at 028a1a1 stands. Since then the pull only restructures the tail of caught_up in private.rs. The old nested if let blocks became an Option chain. The behavior is the same. A background sync still runs only when the entry has a remote and is no longer fresh. It still runs sync_viewed with the viewer's context and still records remember_viewed on success. The catching key is still cleared as soon as the lock is taken. I found nothing to ask for. I did not check the test and e2e runs, so a failure there is for the checks to report.
My approval at 05b17e5 stands. Since then the pull changes one line in caught_up in private.rs: stale(&**e) became stale(e). That drops a redundant reborrow and behaves the same. I found nothing to ask for. I did not check the test and e2e runs, so a failure there is for the checks to report.
Carried forward: the change this pull makes at c35b5113f2e0c3c3d4618cfa2aefd3b8a2a8a2cc is the one reviewed at 262f790d2e2a0f40a219a3a385fbada2ffc770e3, so that review stands. What is new comes from its base.
8 passed, 3 skipped
Looking at a private repository no longer waits on its mirror's sync each time something is written to its space. On knotless.dev every check a runner filed for spec-pds, and every push, made the next look at its page sync first, and the page's five requests all waited on that one sync: 100 of the mirror's 124 syncs in twelve hours ran inside a page's request. Those syncs now run in the background while the page is shown what was last synced, as public repositories already are.
Claude Opus 5.5 · high
What changes
A change syncs the private mirrors viewers are reading, in the background. When the space's sync finds something written there (a push, a runner's check, an issue), or the owner's account changes, the server starts a sync of every viewer's mirror of that repository whose viewer was proven within the minute. There is one task per mirror at a time: a change that comes while one is waiting does not start another.
A page's read is served the mirror as last synced while that sync runs. The reads of a repository's code that 744499d2 let public repositories answer without waiting (
getRepo,getTree,getLastCommits,listBranches,listTags) now do the same for private ones. Each viewer's mirror as last synced is kept apart from the lock its sync holds (App::viewed_last). It is served for ten seconds from the first change, under the same rule (serves, which now takes whether the mirror is quiet rather than an event stamp). It is served only while the space is followed and was synced lately, and only to a viewer proven withinREPROVE, the same minute that already let a read skip asking the owner's PDS. A read served this way still makes its reader the space's syncer (keep), as every read did. A viewer whose proof has lapsed is proven again first, then served the same way, and that read starts the sync itself. Concurrent reads of one repository do not even queue on its lock now, and a sync of one mirror is shared by every read that comes during it.Read-your-writes is kept. A write from the pages bumps the owner's writes, so the reads after it wait for its sync, as before. A read that comes with a delegation token always waits too: that is how the command line shows the appview what it just pushed (
show_appview), and how clients read.located_for_readertakes theArc<App>it spawns with, soRepo::find_for_readerandfound_for_readerdo too, andweb/repo.rsparses the record URI in a sharedrepo_uri. The rest ofas_vieweris the same, split intofresh_viewedandresync, which the background sync reuses.Why
From
admin_logs --message "mirror sync"(the last 500 lines, 06:48 to 19:14 UTC on Nov 10), with each line's trace read back:knotless/0.12.0, itsshow_appviewafter a push.duration_ms - records_ms< 50 ms): nothing in the repository's git had changed.What triggers them: the space's
moves. The runners file their checks into the space (knotless-runwritesdev.knotless.checkwithcom.atproto.space.putRecord). Each write is announced through notifyWrite,spaces::followsyncs the space, finds a write, and callsApp::moved, so the private mirror counts as stale. The page's/_live/reposees the index change and draws the page again, and its five reads synced inline. The browser syncs line up with spec-pds's runs: syncs at 18:47:26 and 18:47:48 around a run at 18:47:44; at 18:59:13, 18:59:21, 18:59:42, 19:00:23 and 19:00:27 around runs at 18:59:09, 18:59:38 and 19:00:21; at 18:02:32 to 18:02:54 around runs at 18:02:31 and 18:02:50. Changes in the owner's account (heard_of) mark it stale the same way. TTL and the viewer's proof are not triggers: the space is followed, and a lapsed proof only asks for a credential again. Nospace not syncedlines name spec-pds. Public repositories avoided this since 744499d2, but private reads went throughas_viewer, which always synced inline, and nothing refreshed a private mirror in the background:heard_ofspawns refreshes only forApp::repos, the public entries.Making the space's moves finer, so that a check written there did not count as a change to the mirror, would cut the syncs themselves. But
movesis counted per space, not per writer or collection, and that is a larger change than this one. It does not rule it out.How it was checked
a_stale_mirror_is_served_while_it_syncsis updated for the newservessignature.private_repositories_indexed_herealready reads a private repository as a member, then pushes and waits for the push to show, which now goes through the background sync and the served-stale read. It gains a second push withreproveat 0, so the read that proves the viewer again is served the mirror as it was and starts the sync, and the push shows once that sync is done. Nothing was built or run here (cargo fmtonly); the rest is left to CI.After this deploys,
knotless admin logs --message "mirror sync"should show spec-pds's syncs without atrace_id, outside page requests, except right after a write from the pages, a read whose viewer must be proven again more than ten seconds after a change, and the command line's own reads.Shortcomings
Changeset: none