fix(nip46): retry the auto-name kind-0 fetch up to 4x, log each attempt

Live Sep 25: nos.lol — the only relay holding the account's kind-0 —
502'd EVERY connecting client (any UA, nostr-sdk and raw websockets
alike) for minutes at a time, then served the event within 2s. The
single-shot enrichment task gave up once and left the profile on the
seed label permanently. Now: 4 attempts, 20s pause between, 75s budget
each (> fetch_profile_metadata's 10s connect-wait + per-relay fetches),
with a pairing_trace line naming the outcome of every attempt so the
next occurrence is diagnosable from pairing-trace.log alone.

216 unit + 5 e2e green, clippy 0, fmt clean, release rebuilt.
This commit is contained in:
Avi 2026-09-25 17:10:39 -05:00
commit bc736ff339

View file

@ -2337,20 +2337,49 @@ impl Nip46ClientSigner {
// fetch_profile_metadata waits up to 10s for the pool to // fetch_profile_metadata waits up to 10s for the pool to
// connect (relay.nostr.band is a known handshake-hanger and // connect (relay.nostr.band is a known handshake-hanger and
// sits in the user's relay list), then fetches per relay. // sits in the user's relay list), then fetches per relay.
// A 10s outer timeout killed the task during the connect // Retry a few times with a pause: live Sep 25 nos.lol — the
// wait — live Sep 25: nos.lol held the account's kind-0 // only relay holding the account's kind-0 — 502'd every
// ('web5osint') but the profile kept the seed label. // client for minutes, then served it fine. A single-shot
let meta = match tokio::time::timeout( // attempt turns such a blip into a permanently generic
Duration::from_secs(30), // label.
tokio::task::spawn_blocking(move || { let mut meta = None;
profiles::fetch_profile_metadata(&identity, &relays_for_meta) for attempt in 1..=4 {
}), match tokio::time::timeout(
) Duration::from_secs(75),
.await tokio::task::spawn_blocking({
{ let identity = identity;
Ok(Ok(Some(meta))) => meta, let relays_for_meta = relays_for_meta.clone();
_ => return, move || profiles::fetch_profile_metadata(&identity, &relays_for_meta)
}),
)
.await
{
Ok(Ok(Some(found))) => {
meta = Some(found);
break;
}
Ok(Ok(None)) => pairing_trace(&format!(
"auto-name attempt {attempt}: no kind-0 found on any relay"
)),
Ok(Err(join_err)) => pairing_trace(&format!(
"auto-name attempt {attempt}: fetch task panicked: {join_err}"
)),
Err(_) => pairing_trace(&format!(
"auto-name attempt {attempt}: fetch timed out (75s budget)"
)),
}
if attempt < 4 {
tokio::time::sleep(Duration::from_secs(20)).await;
}
}
let meta = match meta {
Some(meta) => meta,
None => return,
}; };
pairing_trace(&format!(
"auto-name: kind-0 fetched (display_name={:?} name={:?})",
meta.display_name, meta.name
));
let mut app = app.lock().await; let mut app = app.lock().await;
let mut changed = false; let mut changed = false;
if let Some(row) = app if let Some(row) = app