Skip to content

Commit 4094273

Browse files
fix: Avoids unstructured task
1 parent 34268d3 commit 4094273

File tree

3 files changed

+19
-71
lines changed

3 files changed

+19
-71
lines changed

Sources/GraphQL/Subscription/Subscribe.swift

Lines changed: 16 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -38,43 +38,21 @@ func subscribe(
3838
)
3939

4040
return sourceResult.map { sourceStream in
41-
// We must create a new AsyncSequence because AsyncSequence.map requires a concrete type
42-
// (which we cannot know),
43-
// and we need the result to be a concrete type.
44-
let subscriptionStream = AsyncThrowingStream<GraphQLResult, Error> { continuation in
45-
let task = Task {
46-
do {
47-
for try await eventPayload in sourceStream {
48-
// For each payload yielded from a subscription, map it over the normal
49-
// GraphQL `execute` function, with `payload` as the rootValue.
50-
// This implements the "MapSourceToResponseEvent" algorithm described in
51-
// the GraphQL specification. The `execute` function provides the
52-
// "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the
53-
// "ExecuteQuery" algorithm, for which `execute` is also used.
54-
let newEvent = try await execute(
55-
queryStrategy: queryStrategy,
56-
mutationStrategy: mutationStrategy,
57-
subscriptionStrategy: subscriptionStrategy,
58-
schema: schema,
59-
documentAST: documentAST,
60-
rootValue: eventPayload,
61-
context: context,
62-
variableValues: variableValues,
63-
operationName: operationName
64-
)
65-
continuation.yield(newEvent)
66-
}
67-
continuation.finish()
68-
} catch {
69-
continuation.finish(throwing: error)
70-
}
71-
}
72-
73-
continuation.onTermination = { @Sendable reason in
74-
task.cancel()
75-
}
41+
return AsyncThrowingStream<GraphQLResult, Error> {
42+
var iterator = sourceStream.makeAsyncIterator()
43+
let eventPayload = try await iterator.next()
44+
return try await execute(
45+
queryStrategy: queryStrategy,
46+
mutationStrategy: mutationStrategy,
47+
subscriptionStrategy: subscriptionStrategy,
48+
schema: schema,
49+
documentAST: documentAST,
50+
rootValue: eventPayload,
51+
context: context,
52+
variableValues: variableValues,
53+
operationName: operationName
54+
)
7655
}
77-
return subscriptionStream
7856
}
7957
}
8058

@@ -111,7 +89,7 @@ func createSourceEventStream(
11189
context: Any,
11290
variableValues: [String: Map] = [:],
11391
operationName: String? = nil
114-
) async throws -> Result<any AsyncSequence, GraphQLErrors> {
92+
) async throws -> Result<any AsyncSequence & Sendable, GraphQLErrors> {
11593
// If a valid context cannot be created due to incorrect arguments,
11694
// this will throw an error.
11795
let exeContext = try buildExecutionContext(
@@ -141,7 +119,7 @@ func createSourceEventStream(
141119

142120
func executeSubscription(
143121
context: ExecutionContext
144-
) async throws -> Result<any AsyncSequence, GraphQLErrors> {
122+
) async throws -> Result<any AsyncSequence & Sendable, GraphQLErrors> {
145123
// Get the first node
146124
let type = try getOperationRootType(schema: context.schema, operation: context.operation)
147125
var inputFields: OrderedDictionary<String, [Field]> = [:]

Tests/GraphQLTests/SubscriptionTests/SubscriptionSchema.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ let EmailQueryType = try! GraphQLObjectType(
9090

9191
class EmailDb {
9292
var emails: [Email]
93-
let publisher: SimplePubSub<Any>
93+
let publisher: SimplePubSub<Email>
9494

9595
init() {
9696
emails = [
@@ -101,7 +101,7 @@ class EmailDb {
101101
unread: false
102102
),
103103
]
104-
publisher = SimplePubSub<Any>()
104+
publisher = SimplePubSub<Email>()
105105
}
106106

107107
/// Adds a new email to the database and triggers all observers

Tests/GraphQLTests/SubscriptionTests/SubscriptionTests.swift

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -857,35 +857,5 @@ class SubscriptionTests: XCTestCase {
857857
// Handled by AsyncThrowingStream
858858

859859
/// Test incorrect emitted type errors
860-
func testErrorWrongEmitType() async throws {
861-
let db = EmailDb()
862-
let stream = try await db.subscription(query: """
863-
subscription ($priority: Int = 0) {
864-
importantEmail(priority: $priority) {
865-
email {
866-
from
867-
subject
868-
}
869-
inbox {
870-
unread
871-
total
872-
}
873-
}
874-
}
875-
""")
876-
var iterator = stream.makeAsyncIterator()
877-
878-
db.publisher.emit(event: "String instead of email")
879-
880-
let result = try await iterator.next()
881-
XCTAssertEqual(
882-
result,
883-
GraphQLResult(
884-
data: ["importantEmail": nil],
885-
errors: [
886-
GraphQLError(message: "String is not Email"),
887-
]
888-
)
889-
)
890-
}
860+
// Handled by strongly typed PubSub
891861
}

0 commit comments

Comments
 (0)