Move GeoRelay fetch work off the main actor (#1060)

* Run GeoRelay fetch pipeline off main actor

* Capture GeoRelay session before detached fetch

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
This commit is contained in:
jack
2026-03-12 20:24:47 -10:00
committed by GitHub
co-authored by jack
parent 7d83310bc2
commit c88ab3dd05
2 changed files with 114 additions and 32 deletions
@@ -145,6 +145,34 @@ final class GeoRelayDirectoryTests: XCTestCase {
XCTAssertEqual(forcedRequestCount, 1)
}
func test_prefetchIfNeeded_runsRemoteFetchOffMainThread() async {
var factoryThreadFlags: [Bool] = []
let threadRecorder = MainThreadRecorder()
let harness = makeHarness(
fetchCSV: """
relay url,lat,lon
background.example,8,9
""",
fetchFactoryObserver: {
factoryThreadFlags.append(isExecutingOnMainThread())
},
fetchObserver: {
await threadRecorder.record(isExecutingOnMainThread())
}
)
let directory = GeoRelayDirectory(dependencies: harness.dependencies)
directory.prefetchIfNeeded()
let refreshed = await waitUntil {
directory.entries == [GeoRelayDirectory.Entry(host: "background.example", lat: 8, lon: 9)]
}
XCTAssertTrue(refreshed)
XCTAssertEqual(factoryThreadFlags, [true])
let recordedValues = await threadRecorder.recordedValues()
XCTAssertEqual(recordedValues, [false])
}
func test_prefetchIfNeeded_failureSchedulesRetryAndRecoversOnNextFetch() async {
let csv = """
relay url,lat,lon
@@ -215,6 +243,8 @@ final class GeoRelayDirectoryTests: XCTestCase {
workingDirectoryCSV: String? = nil,
fetchCSV: String? = nil,
fetchResults: [Result<Data, Error>] = [],
fetchFactoryObserver: (@MainActor @Sendable () -> Void)? = nil,
fetchObserver: (@Sendable () async -> Void)? = nil,
autoStart: Bool = false,
activeNotificationName: Notification.Name? = nil
) -> GeoRelayHarness {
@@ -254,8 +284,12 @@ final class GeoRelayDirectoryTests: XCTestCase {
retryInitialSeconds: 5,
retryMaxSeconds: 40,
awaitTorReady: { true },
fetchData: { request in
try await fetcher.fetch(request)
makeFetchData: {
fetchFactoryObserver?()
return { request in
await fetchObserver?()
return try await fetcher.fetch(request)
}
},
readData: { url in
fileStore.dataByURL[url]
@@ -359,6 +393,22 @@ private actor RetryDelayRecorder {
}
}
private actor MainThreadRecorder {
private var values: [Bool] = []
func record(_ value: Bool) {
values.append(value)
}
func recordedValues() -> [Bool] {
values
}
}
private enum GeoRelayTestError: Error {
case network
}
private func isExecutingOnMainThread() -> Bool {
Thread.isMainThread
}