sign_and_send_to_nostr → publish_nostr_event has no relay timeout — hangs uvicorn forever on first signup if external relays unreachable #7
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Symptom
provision_merchant→sign_and_send_to_nostr→nostr_client.publish_nostr_event(event)blocks indefinitely waiting for relay acks when the configured external relays are unreachable from the lnbits process. Because eager default-merchant provisioning (aiolabs/lnbits#46) is awaited inline in thePOST /api/v1/auth/registerhandler, the entire signup HTTP request hangs forever — not just 15 s, forever — and the uvicorn worker is stuck on it. Subsequent register attempts also hang (the worker pool is exhausted) until lnbits is restarted.This reproduces with or without the NIP-46 bunker in the path. Even when
LNBITS_NSEC_BUNKER_URLis unset and the account usesLocalSigner(sosign_eventreturns instantly without any network round-trip), the subsequentpublish_nostr_eventto external relays still hangs without bound.Reproduction (regtest dev stack)
LNBITS_NSEC_BUNKER_URLunset (LocalSigner path).LNBITS_USER_DEFAULT_EXTENSIONSincludesnostrmarketso newly-created accounts get the extension assigned, which triggers_create_default_merchantinsidecreate_user_account_no_check.nostr_clientare otherwise unreachable).POST /api/v1/auth/registerfor a new user.Created default nostrmarket merchantlog (success), noFailed to provision default nostrmarket merchantlog (caught exception). Just silence.database.sqlite3(accountsandext_nostrmarket.sqlite3merchantsboth have rows for the user) — only the request response never comes back./api/v1/auth, future/auth/registercalls) start hanging too, because uvicorn workers are stuck. Login becomes impossible until lnbits restart.Where the hang is
The outer
try: ... except Exception as ex: logger.warning(...)inprovision_merchant(line 240+) only catches raised exceptions — it doesn't unblock an indefinite await. Sincepublish_nostr_eventdoesn't raise on unreachable relays, control never returns.Suggested fix
Wrap the publish call in
asyncio.wait_forwith a bounded timeout (e.g. 10 s, matching the bunker NIP-46 timeout convention), or fire-and-forget the publish viaasyncio.create_task(...)so signup completes immediately while the publish retries in the background. The merchant row is already persisted in DB at this point — the kind:30017 stall event can be re-published later via the existing health-monitor / subscription-resubscribe loop.A fire-and-forget pattern is preferable since the signup endpoint doesn't actually depend on the publish result.
Context
nostrmarketfromlnbits_user_default_extensionsso new signups skip merchant provisioning. That's not a real fix — anyone withnostrmarketin their defaults hits this whenever their relay set is degraded.private_keyargument and TypeErrors out beforesign_and_send_to_nostr, or (b) configured relays are reachable. Both protective factors are fragile.🤖 Generated with Claude Code