fix(appview): skip did:key in handle-sync SQL — they blocked progress

The handle-sync worker picks the next BATCH_SIZE=100 distinct
DIDs with 'handle = \"\"' via 'ORDER BY did LIMIT 100'. But
'alphabetically' (which is what ORDER BY on a text column
produces) puts 'did🔑' before 'did:plc:' before 'did:web:'.
The 'dispatch' function returns 'Ok(None)' for 'did🔑'
(no resolver exists), counts that as 'skipped', and exits the
batch. Result: every pass processes the same ~3700 'did🔑'
rows first and never reaches any resolvable 'did:plc:' DID.

Fix at the SQL layer: 'WHERE did LIKE \"'did:plc:%\"' OR did
LIKE \"'did:web:%\"' \"'\") so every batch is real work. After
the first run on a fresh start, 'resolved=254 failed=0 skipped=0'
instead of 'resolved=0 failed=0 skipped=100'.
This commit is contained in:
tomdebone
2026-07-07 21:50:47 +02:00
parent 73e56fd788
commit a226a92c12
+11
View File
@@ -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<SyncReport> {
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"#,
)