`provision_merchant` is awaited inline by lnbits's eager default-merchant
hook (lnbits/core/services/users.py::_create_default_merchant,
aiolabs/lnbits#46). The pre-fix code inline-awaited
`sign_and_send_to_nostr(merchant, default_stall)`, whose terminal
`nostr_client.publish_nostr_event` has no per-relay deadline — every
configured external relay being unreachable from the lnbits process
pinned the uvicorn worker on `POST /auth/register` forever, with no
exception ever raised. Subsequent signup / login attempts then queued
behind that worker, locking out the instance until restart.
This was filed as aiolabs/nostrmarket#7 and reproduces deterministically
on the regtest dev stack whenever external relays aren't reachable from
the docker network. The same hang reproduces whether or not the NIP-46
bunker is in the loop — the publish is the culprit, not the signer.
Fix:
- Schedule the publish via `asyncio.create_task(...)`. The signup
response returns immediately after the DB rows we control are
committed; the publish completes (or fails, or times out) in the
background. Matches the existing comment "Non-fatal on failure: a
later product publish (or webapp self-heal) will retry."
- Wrap the background publish in `asyncio.wait_for` with a 30 s cap so
a permanently-unreachable relay set doesn't leave an asyncio task
pinned for the lifetime of the uvicorn process. Timeout logs at
warning; `event_id` simply stays NULL on the stall row until a later
republish lands it.
Verified locally (regtest, bunker disabled, LocalSigner path):
- signup `POST /auth/register` returns in <3 s with a valid JWT
- background publish lands the kind-30017 stall event on the relay
~12 s later
- merchant / stall rows persist with the expected names
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>