Reduce race condition probability in Ndb streaming functions

This attempts to reduce race conditions coming from Ndb streaming
functions that could lead to lost notes or crashes.

It does so by making two improvements:
1. Instead of callbacks, now the callback handler uses async streams,
   which reduces the chances of a callback being called before the last
   item was processed by the consumer.
2. The callback handler will now queue up received notes if there are
   no listeners yet. This is helpful because we need to issue the
   subscribe call to nostrdb before getting the subscription id and
   setting up a listener, but in between that time nostrdb may still
   send notes which would effectively get dropped without this queuing
   mechanism.

Changelog-Fixed: Improved robustness in the part of the code that streams notes from nostrdb
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit is contained in:
Daniel D’Aquino
2025-10-24 16:22:26 -07:00
parent 10b4d804f8
commit 7afcaa99fe
2 changed files with 62 additions and 29 deletions

View File

@@ -42,6 +42,7 @@ class NostrNetworkManagerTests: XCTestCase {
func ensureSubscribeGetsAllExpectedNotes(filter: NostrFilter, expectedCount: Int) async {
let endOfStream = XCTestExpectation(description: "Stream should receive EOSE")
let atLeastXEvents = XCTestExpectation(description: "Stream should get at least the expected number of notes")
var receivedCount = 0
var eventIds: Set<NoteId> = []
Task {
@@ -55,6 +56,9 @@ class NostrNetworkManagerTests: XCTestCase {
}
eventIds.insert(event.id)
}
if eventIds.count >= expectedCount {
atLeastXEvents.fulfill()
}
case .eose:
continue
case .ndbEose:
@@ -66,7 +70,7 @@ class NostrNetworkManagerTests: XCTestCase {
}
}
}
await fulfillment(of: [endOfStream], timeout: 15.0)
await fulfillment(of: [endOfStream, atLeastXEvents], timeout: 15.0)
XCTAssertEqual(receivedCount, expectedCount, "Event IDs: \(eventIds.map({ $0.hex() }))")
}