gqlgen
gqlgen copied to clipboard
Can't find docs/examples of Subscriptions
What happened?
I want to write a Subscription resolver
- Looked through this repo
- Looked through https://gqlgen.com
What did you expect?
- Expected to find a section called "Subscriptions" explaining how to write them with gqlgen
More info
Through some issue searching I found a link to this: https://github.com/99designs/gqlgen/blob/master/example/chat/resolvers.go#L115-L150
That's what I'm working off of currently. It would be useful to have some part of the docs touch on subscriptions.
While the chat example is a good starting point, it misses in my opinion two important parts:
- The channel is not closed in the cleanup. This leads to
gqlgen
never being able to terminate the internal go routine.
go func() {
<-ctx.Done()
r.mu.Lock()
delete(room.Observers, id)
close(events) // <-
r.mu.Unlock()
}()
- The lock in this case can get blocked when there are connection issues with one client. The example buffers the channel, but I would argue that at some point the message should just be dropped so that no other clients are blocked from receiving messages.
r.mu.Lock()
for _, observer := range room.Observers {
if observer.Username == "" || observer.Username == message.CreatedBy {
select {
case observer.Message <- &message:
default:
log.Printf("could not send message to %v\n", observer.Username)
}
}
}
r.mu.Unlock()
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Yes, it would be nice to have some documentation on subscriptions. I have been trying to figure out how they work.
The only other reference I can find is https://www.freecodecamp.org/news/https-medium-com-anshap1719-graphql-subscriptions-with-go-gqlgen-and-mongodb-5e008fc46451/
The only other reference I can find is https://www.freecodecamp.org/news/https-medium-com-anshap1719-graphql-subscriptions-with-go-gqlgen-and-mongodb-5e008fc46451/
I got them working with arsmn's fork for gofiber framework. However, I am having an issue where I get an error whenever a user abruptly closes the subscription by closing the browser window/tab
https://github.com/99designs/gqlgen/issues/1281
Bump
Bump
bump
The only other reference I can find is https://www.freecodecamp.org/news/https-medium-com-anshap1719-graphql-subscriptions-with-go-gqlgen-and-mongodb-5e008fc46451/
FWIW: this is the original post on medium, which doesn't have broken formatting: https://medium.com/@anshap1719/how-to-handle-graphql-subscriptions-with-go-gqlgen-and-mongodb-1152ee6da82d
Bump
Why they can't do it in over a year?
Hey everyone,
I've just done the PR #2346 containing my suggestion for the documentation on Subscriptions. I'd be happy if you could all proof-read my document, and give me feedback if anything is unclear or if I did any typos! 🙂
Thanks @Unkn0wnCat for great Subscriptions recipe! On another note i'm wondering why there is not example of GraphQL client written in Go that subsribes to a subscription? All examples I've seen are NodeJS wondering what is the reason.
Thanks for the docs @Unkn0wnCat It has showed me direction to go however coming from node.js background. There are few concepts like event triggers based on topics like it is shown here I am now wondering how to implement this in go. Can we have similar things to those?
Also I used to see pub/sub things much in nodejs like using Redis or Google pub sub? Do we need the same things in golang?
@AndriyKalashnykov I've not had to implement a subscriptions client in Go myself, but it looks like hasura/go-graphql-client has the feature you're looking for. Keep in mind I've not worked with the linked module, so I can't give you any rating or pointers on the quality of it, but it has a lot of stars as well as an active maintainer - so give it a try!
@kateile In the reference example in the recipe I've left off with the Go routine having an open channel, on top of that you could easily build your own topic-subscriptions or use a module like Google's PubSub, or a Redis client.
Something like this may work for Redis (no warranty on that, I've just typed this off the top of my head, not tried nor compiled it):
func (r *subscriptionResolver) CurrentTime(ctx context.Context) (<-chan *model.Time, error) {
ch := make(chan *model.Time)
rdb := GetRedisInstance() // You'll need to provide your own redis client instance 😛
go func() {
for {
pubsub := rdb.Subscribe(ctx, "timechannel")
incoming := pubsub.Channel()
for msg := range incoming {
myObject := UnmarshalMyObject(msg.Payload) // You'll somehow need to transform your Redis payload into the right object
select {
case ch <- myObject:
default:
fmt.Println("Channel closed.")
pubsub.Close()
return
}
}
close(ch)
}
}()
return ch, nil
}
Hope this helps for both of you!