From bc736ff339adf60cddc2d54ca30e0613648f2cea Mon Sep 17 00:00:00 2001 From: Avi Date: Fri, 25 Sep 2026 17:10:39 -0500 Subject: [PATCH] fix(nip46): retry the auto-name kind-0 fetch up to 4x, log each attempt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/signer/nip46_client.rs | 55 +++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/src/signer/nip46_client.rs b/src/signer/nip46_client.rs index 198b3c4..44ddf95 100644 --- a/src/signer/nip46_client.rs +++ b/src/signer/nip46_client.rs @@ -2337,20 +2337,49 @@ impl Nip46ClientSigner { // fetch_profile_metadata waits up to 10s for the pool to // connect (relay.nostr.band is a known handshake-hanger and // sits in the user's relay list), then fetches per relay. - // A 10s outer timeout killed the task during the connect - // wait — live Sep 25: nos.lol held the account's kind-0 - // ('web5osint') but the profile kept the seed label. - let meta = match tokio::time::timeout( - Duration::from_secs(30), - tokio::task::spawn_blocking(move || { - profiles::fetch_profile_metadata(&identity, &relays_for_meta) - }), - ) - .await - { - Ok(Ok(Some(meta))) => meta, - _ => return, + // Retry a few times with a pause: live Sep 25 nos.lol — the + // only relay holding the account's kind-0 — 502'd every + // client for minutes, then served it fine. A single-shot + // attempt turns such a blip into a permanently generic + // label. + let mut meta = None; + for attempt in 1..=4 { + match tokio::time::timeout( + Duration::from_secs(75), + tokio::task::spawn_blocking({ + let identity = identity; + let relays_for_meta = relays_for_meta.clone(); + 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 changed = false; if let Some(row) = app