Subscription resolvers in GraphQL - Time & Space Complexity
When using subscription resolvers in GraphQL, it's important to understand how the time to process events grows as more clients subscribe or more events occur.
We want to know how the work done changes when the number of subscribers or events increases.
Analyze the time complexity of the following subscription resolver code snippet.
subscription {
messageAdded(roomId: "123") {
id
content
sender
}
}
// Resolver listens for new messages in a chat room and pushes updates to subscribers.
This code listens for new messages in a chat room and sends updates to all clients subscribed to that room.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Sending updates to each subscriber when a new message arrives.
- How many times: Once per new message, repeated for every subscriber in the room.
As the number of subscribers grows, the work to send updates grows too.
| Input Size (subscribers) | Approx. Operations (send updates) |
|---|---|
| 10 | 10 sends per message |
| 100 | 100 sends per message |
| 1000 | 1000 sends per message |
Pattern observation: The number of operations grows directly with the number of subscribers.
Time Complexity: O(n)
This means the time to send updates grows linearly with the number of subscribers.
[X] Wrong: "Sending updates to subscribers happens instantly no matter how many there are."
[OK] Correct: Each subscriber needs its own update, so more subscribers mean more work and more time.
Understanding how subscription resolvers scale helps you explain real-time data flow and performance in apps, a useful skill for many projects.
"What if we batch updates to subscribers instead of sending individually? How would the time complexity change?"
Practice
subscription resolver in GraphQL?Solution
Step 1: Understand the role of subscription resolvers
Subscription resolvers are designed to send data updates automatically as events happen, unlike queries which fetch data once.Step 2: Compare with other resolver types
Queries fetch data once, mutations modify data, and schema defines types. Only subscriptions provide live updates.Final Answer:
To provide real-time updates to clients when data changes -> Option CQuick Check:
Subscription = real-time updates [OK]
- Confusing subscriptions with queries
- Thinking subscriptions modify data
- Mixing schema definition with resolver purpose
Solution
Step 1: Identify the correct GraphQL operation keyword
Subscriptions use thetype Subscriptionkeyword to declare real-time data streams in the schema.Step 2: Check other operation keywords
Queries usetype Query, mutations usetype Mutation, andtype Resolveris not a valid keyword.Final Answer:
type Subscription { newMessage: Message } -> Option AQuick Check:
Subscription keyword = subscription declaration [OK]
- Using 'type Query' or 'type Mutation' instead of 'type Subscription'
- Trying to use 'type Resolver' keyword
- Misplacing subscription declaration outside schema
const resolvers = {
Subscription: {
newMessage: {
subscribe: () => pubsub.asyncIterator(['MESSAGE_ADDED'])
}
}
};Solution
Step 1: Understand the subscribe function
Thesubscribefunction returns an async iterator for the event 'MESSAGE_ADDED', so it listens for new messages.Step 2: Determine what triggers updates
Updates are sent only when the 'MESSAGE_ADDED' event occurs, so clients get notified only on new messages.Final Answer:
The client receives updates only when a message is added -> Option AQuick Check:
Subscription triggers on event = client updates [OK]
- Assuming all past data is sent immediately
- Thinking updates require queries first
- Missing that subscribe returns async iterator
const resolvers = {
Subscription: {
newNotification: {
subscribe: pubsub.asyncIterator('NOTIFICATION_ADDED')
}
}
};Solution
Step 1: Check the subscribe property type
Thesubscribeproperty must be a function that returns the async iterator, not the async iterator itself.Step 2: Verify correct usage of asyncIterator
It should besubscribe: () => pubsub.asyncIterator('NOTIFICATION_ADDED')to work properly.Final Answer:
The subscribe function should be a function returning asyncIterator, not the asyncIterator itself -> Option DQuick Check:
Subscribe must be a function returning asyncIterator [OK]
- Assigning asyncIterator directly instead of a function
- Using string instead of array for event names (optional)
- Confusing subscription with query resolvers
const resolvers = {
Subscription: {
commentAdded: {
subscribe: (parent, args, { pubsub }) => {
return pubsub.asyncIterator('COMMENT_ADDED');
},
resolve: (payload, args) => {
if (payload.postId === args.postId) {
return payload;
}
return null;
}
}
}
};Solution
Step 1: Understand event filtering in subscriptions
Theresolvefunction can filter events by checking if the payload matches the subscription arguments.Step 2: Check the given code logic
The code returns the payload only ifpayload.postId === args.postId, otherwise returns null to skip irrelevant events.Final Answer:
This implementation correctly filters comments by postId in the resolve function -> Option BQuick Check:
Filtering in resolve function = correct approach [OK]
- Trying to filter inside subscribe instead of resolve
- Expecting asyncIterator to filter by arguments automatically
- Believing subscriptions cannot filter events
Ready to prove it?
Pass the test and this pattern moves unknown
