A slow relay ack stalls the whole Nostr worker
- 主要語言
- Rust
- 星號
- 71
- 分支
- 5
- 平均合併
- 4 小時 2 分鐘
- 30 天內合併 PR
- 31
描述
Found while reviewing #513. Pre-existing — #513 neither causes nor worsens it — but that PR makes it visible for the first time, and turns it into something a future change could break silently.
## What happens
`run_subscription_loop` awaits `handle_command` inline inside its `select!` arm (`src/infrastructure/subscription/nostr.rs`). `NostrCommand::SendEventBuilder` awaits `client.send_event(&event).await`, which waits for relay `OK` acknowledgements — nostr-sdk's default is 10s, plus another 10s if NIP-42 authentication is involved.
For that whole window the loop is inside the arm, not at the `select!`. So it processes:
- **no relay notifications** — the timeline stops updating,
- **no other commands** — opening a tab, loading more, and unsubscribing all do nothing.
Worse, `NotificationStream` skips broadcast lag, so events arriving while the loop is blocked can be dropped outright rather than delayed.
Scenario: post a note to a relay that accepts the connection but never acks. For the next ten seconds the feed is frozen, `j`/`k` scroll a timeline nothing is being added to, and pressing `t` to open a tab appears to do nothing.
Before #513 the only sign was the freeze itself. #513 now shows `[Sending] …` for the same window, which makes the cause legible — and makes it obvious the app is waiting on something.
## Why it cannot simply be spawned
The obvious fix — `tokio::spawn` the send instead of awaiting it — would break #513's publish reporting. That design matches `EventPublished` reports to submissions **by position**, which is sound only because the worker never has two publishes outstanding. Spawning would let reports arrive out of order and settle outcomes against the wrong publish: `[Posted] `.
So this needs a correlation id on the command and the report before the concurrency can change. There is a comment at the `select!` arm saying so.
## Suggested shape
- Give `NostrCommand::SendEventBuilder` an id, echo it on `EventPublished`, and have `AppState` match on it instead of on queue position. That removes the ordering dependency.
- Then let sends run concurrently with the notification arm — either by spawning them or by moving publishes onto their own task with their own queue.
- Consider whether other long-awaiting commands (`LoadMore`, the initial contact-list fetch) want the same treatment.
## Acceptance
- Posting to an unresponsive relay does not stop the timeline updating.
- Two publishes in flight at once settle against the right submissions.
- No relay notification is dropped because the worker was busy sending.
貢獻指南
評估
這個 Issue 還沒有評估資料。