diff --git a/crates/appview/src/handle_sync.rs b/crates/appview/src/handle_sync.rs index b72ad0d..45e62c4 100644 --- a/crates/appview/src/handle_sync.rs +++ b/crates/appview/src/handle_sync.rs @@ -112,11 +112,22 @@ impl HandleSyncWorker { /// One bounded scan: find up to [`BATCH_SIZE`] distinct DIDs whose /// posts have an empty handle, resolve them, and update the rows /// where the handle is still empty (race-safe). + /// + /// **SQL-level filter**: we exclude `did:key:` entirely because + /// there's no resolver path for them — the PLC directory and the + /// `did:web:` HTTPS resolver both reject non-`did:plc:` / + /// non-`did:web:` DIDs with `Ok(None)`. Previously the worker + /// picked via `ORDER BY did LIMIT 100`, but lexicographically + /// `did:key:` sorts before `did:plc:` / `did:web:`, so the worker + /// would process the same 100 `did:key:` rows every 300 s and + /// never reach any resolvable DID. Filtering at SQL time makes + /// every batch contribute real work. pub async fn run_once(&self) -> Result { let dids: Vec<(String,)> = sqlx::query_as( r#"SELECT DISTINCT did FROM posts WHERE handle = '' + AND (did LIKE 'did:plc:%' OR did LIKE 'did:web:%') ORDER BY did LIMIT $1"#, )