Skip to content

Commit a5ec37e

Browse files
committed
Convert Ingestion.fetchMetadata
1 parent 0d38a03 commit a5ec37e

1 file changed

Lines changed: 52 additions & 16 deletions

File tree

Sources/App/Commands/Ingestion.swift

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -271,30 +271,66 @@ enum Ingestion {
271271
throw Github.Error.requestFailed(.internalServerError)
272272
}
273273

274-
// Need to pull in github functions individually, because otherwise the `async let` will trigger a
275-
// concurrency error if github gets used more than once:
276-
// Sending 'github' into async let risks causing data races between async let uses and local uses
277-
@Dependency(\.github.fetchMetadata) var fetchMetadata
278-
@Dependency(\.github.fetchLicense) var fetchLicense
279-
@Dependency(\.github.fetchReadme) var fetchReadme
274+
// 2026-04-08, sas: revert this back to `async let` instead of `withThrowingTaskGroup` when a fix for https://github.com/swiftlang/swift/issues/75501 is available.
275+
do {
276+
enum FetchResult: Sendable {
277+
case metadata(Github.Metadata)
278+
case license(Github.License?)
279+
case readme(Github.Readme?)
280+
}
280281

281-
async let metadata = try await fetchMetadata(owner, repository)
282-
async let license = await fetchLicense(owner, repository)
283-
async let readme = await fetchReadme(owner, repository)
282+
let results = try await withThrowingTaskGroup(of: FetchResult.self) { group in
283+
group.addTask {
284+
@Dependency(\.github.fetchMetadata) var fetchMetadata
285+
return .metadata(try await fetchMetadata(owner, repository))
286+
}
287+
group.addTask {
288+
@Dependency(\.github.fetchLicense) var fetchLicense
289+
return .license(await fetchLicense(owner, repository))
290+
}
291+
group.addTask {
292+
@Dependency(\.github.fetchReadme) var fetchReadme
293+
return .readme(await fetchReadme(owner, repository))
294+
}
284295

285-
do {
286-
return try await (metadata, license, readme)
296+
var results = [FetchResult]()
297+
for try await result in group {
298+
results.append(result)
299+
}
300+
return results
301+
}
302+
303+
var metadata: Github.Metadata?
304+
var license: Github.License?
305+
var readme: Github.Readme?
306+
for res in results {
307+
switch res {
308+
case .metadata(let data):
309+
metadata = data
310+
case .license(let data):
311+
license = data
312+
case .readme(let data):
313+
readme = data
314+
}
315+
}
316+
317+
guard let metadata = metadata else {
318+
struct MetadataIsNil: Swift.Error { }
319+
throw Github.Error.unexpectedError(MetadataIsNil())
320+
}
321+
322+
return (metadata, license, readme)
287323
} catch let error as Github.Error {
288324
throw error
289325
} catch {
290326
// This whole do { ... } catch { ... } should be unnecessary - it's a workaround for
291327
// https://github.com/swiftlang/swift/issues/76169
292-
assert(false, "Unexpected error type: \(type(of: error))")
293-
// We need to throw _something_ here (we should never hit this codepath though)
328+
assert(false, "Unexpected error type: \(type(of: error))")
329+
// We need to throw _something_ here (we should never hit this codepath though)
294330
throw Github.Error.unexpectedError(error)
295-
// We could theoretically avoid this whole second catch and just do
296-
// error as! GithubError
297-
// but let's play it safe and not risk a server crash, unlikely as it may be.
331+
// We could theoretically avoid this whole second catch and just do
332+
// error as! GithubError
333+
// but let's play it safe and not risk a server crash, unlikely as it may be.
298334
}
299335
}
300336

0 commit comments

Comments
 (0)