Open EmrysMyrddin opened 1 month ago
I ended up building this plugin to handle subscriptions in my Fastify setup
import { EOL } from 'os'
export const useSubscription = () => {
return {
async onSubscribe () {
return {
async onSubscribeResult ({
result,
args: {
contextValue: { req, reply }
}
}) {
req.socket.on('end', () => {
result.return()
reply.hijack() // tell Fastify to skip the automatic invocation of reply.send()
})
req.socket.on('close', () => {
reply.log.info(
{
res: reply,
responseTime: reply.elapsedTime
},
'request completed'
)
reply.raw.end() // tell the server that all of the response headers and body have been sent
})
for await (const data of result) {
reply.raw.write(
`event: next${EOL}data: ${JSON.stringify(data)}${EOL}${EOL}`
)
}
}
}
}
}
}
Hopefully this is useful to other devs as well.
GraphQL Yoga doesn't need an extra plugin for SSE except single connection mode. You can see Fastify tests below that use the same path for subscriptions. Maybe you can help us reproducing your issue here; https://github.com/dotansimha/graphql-yoga/blob/main/examples/fastify/__integration-tests__/fastify.spec.ts GraphQL SSE plugin only handles single connection mode of GraphQL SSE protocol, and you can configure the path of that listens the subscriptions; https://github.com/dotansimha/graphql-yoga/blob/main/packages/plugins/graphql-sse/src/index.ts#L17
I'd not use that kind of plugin which bypasses entire Yoga plugin hooks, and it might cause an unexpected behavior.
You are absolutely right. Thanks for your comment. I looked at the test and decided I had to make my implementation work in the correct way.
The issue I had initially was related to how I was setting an initial value for my subscription.
I was doing a pubSub.subscribe
and then used a process.nextTick
to create the first event for my subscription topic.
It was a convoluted solution with some drawbacks (had to make sure the "artificial" event would be issued only to the new subscriber), but it worked.
After migrating to Yoga the process.nextTick
was somehow issued before the subscriber was actually subscribed to the pubSub. Not sure why, but this caused my "artificial" event to not be delivered. Because of this I wrongly assumed that this setup wasn't working.
Now I spent more time into this and figured all this out.
So I removed my custom useSubscription
plugin entirely and switched to a much better solution to deliver my initial data to the subscription with this:
Repeater.merge([
initialData,
pubSub.subscribe(topic)
])
I think I would probably add something to the documentation that documents simple subscriptions without any need for the SSE plugin. Maybe make it more explicit. In any case, this issue can be closed.
Thank you for your feedback!
It seems our documentation still need some update on this ? If it's the case, I will let this issue open to not forget about it :-)
Discussed in https://github.com/dotansimha/graphql-yoga/discussions/3273