Skip to content

Commit 19408ab

Browse files
Merge pull request #172 from NeedleInAJayStack/fix/errorCollection
Fixes concurrency issues with error collection
2 parents 6e483ae + 3aa2ed8 commit 19408ab

File tree

2 files changed

+10
-23
lines changed

2 files changed

+10
-23
lines changed

Sources/GraphQL/Execution/Execute.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,11 @@ public final class ExecutionContext: @unchecked Sendable {
7878
}
7979

8080
public func append(error: GraphQLError) {
81-
errors.append(error)
81+
// `append` must explicitly use the DispatchQueue and the underlying storage because by
82+
// default `append` uses separate unblocked get, modify, and replace steps.
83+
errorsQueue.sync(flags: .barrier) {
84+
self._errors.append(error)
85+
}
8286
}
8387
}
8488

@@ -849,7 +853,7 @@ func completeListValue(
849853

850854
return try await withThrowingTaskGroup(of: (Int, (any Sendable)?).self) { group in
851855
// To preserve order, match size to result, and filter out nils at the end.
852-
var results: [(any Sendable)?] = result.map { _ in nil }
856+
var results = [(any Sendable)?](repeating: nil, count: result.count)
853857
for (index, item) in result.enumerated() {
854858
group.addTask {
855859
// No need to modify the info object containing the path,

Sources/GraphQL/Type/Schema.swift

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,26 +34,9 @@ public final class GraphQLSchema: @unchecked Sendable {
3434
let astNode: SchemaDefinition?
3535
let extensionASTNodes: [SchemaExtensionDefinition]
3636

37-
// Used as a cache for validateSchema().
38-
private var _validationErrors: [GraphQLError]?
39-
private let validationErrorQueue = DispatchQueue(
40-
label: "graphql.schema.validationerrors",
41-
attributes: .concurrent
42-
)
43-
var validationErrors: [GraphQLError]? {
44-
get {
45-
// Reads can occur concurrently.
46-
return validationErrorQueue.sync {
47-
_validationErrors
48-
}
49-
}
50-
set {
51-
// Writes occur sequentially.
52-
return validationErrorQueue.sync(flags: .barrier) {
53-
self._validationErrors = newValue
54-
}
55-
}
56-
}
37+
/// Used as a cache for validateSchema(). Concurrent access is not protected, so assume
38+
/// it can be changed at any time.
39+
var validationErrors: [GraphQLError]?
5740

5841
public let queryType: GraphQLObjectType?
5942
public let mutationType: GraphQLObjectType?
@@ -95,7 +78,7 @@ public final class GraphQLSchema: @unchecked Sendable {
9578
extensionASTNodes: [SchemaExtensionDefinition] = [],
9679
assumeValid: Bool = false
9780
) throws {
98-
_validationErrors = assumeValid ? [] : nil
81+
validationErrors = assumeValid ? [] : nil
9982

10083
self.description = description
10184
self.extensions = extensions

0 commit comments

Comments
 (0)