how do subscriptions work for multiple load balanced websocker servers?
bjm88 opened this issue · 4 comments
We are on latest version of gqlgen, really like it for general graphql work. For subscriptions we are prototyping it and found the chat example:
https://github.com/99designs/gqlgen/blob/master/example/chat/server/server.go
but not any other documentation.
Our primary concern/question is how would multiple servers in a real clustered env (aws/ecs/docker/go gorilla websockets for us) know about changes to properly publish to subscripting UI clients ? Does the framework have a hookup point somewhere to send mutations to a message bus that can notify all servers ? We have an existing redis powered message bus for just this use case in our chat application and could happily use it if we know how to hookup things into the gqlgen framework......
Any information along these lines would be really useful, thank you!
Hi, @bjm88
We make use of go-rscsrv-redigo
which provide PubSub methods. For example:
func (r *subscriptionResolver) BookAdded(ctx context.Context) (<-chan *types.BookAddedPayload, error) {
events := make(chan *types.BookAddedPayload, 1)
go redigorscsrv.DefaultRedigoService.Subscribe(ctx, func() error {
// subscribed to all channels :)
return nil
}, func(channel string, data []byte) error {
var payload types.BookAddedPayload
if err := json.Unmarshal(data, &payload); err != nil {
return err
}
events <- &payload
return nil
}, "bookAdded")
return events, nil
}
Then anywhere in our application, we could publish and information into the bookAdded
channel.
if err := redigorscsrv.DefaultRedigoService.Publish(ctx, "bookAdded", &types.BookAddedPayload{Book: obj}); err != nil {
rlog.Criticalf("unable to publish bookAdded payload: %s", err.Error())
}
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.
I'm getting undefined: redigosrv.DefaultRedigoService
Any update since then ?
@PunkHaz4rd I think the same thing can be with pub/sub with go-redis/redis
redigo also has pubsub but I haven't had time to checked them out.
Here is an example for Sub:
func (s *subscriptionResolver) NewEmails(ctx context.Context) (<-chan *models.Email, error) {
channel := make(chan *models.Email, 1)
go func() {
sub := redisClient.Subscribe(ctx, "email") // redisClient is just a *redis.Client from redis.NewClient()
_, err := sub.Receive(ctx)
if err != nil {
return
}
ch := sub.Channel()
for {
select {
case message := <-ch:
var email models.Email
err := json.Unmarshal([]byte(message.Payload), &email) // use json instead
if err != nil {
log.Println(err)
return
}
channel <- &email
// close when context done
case <-ctx.Done():
sub.Close()
return
}
}
}()
return channel, nil
}
For pub
emailJSON, err := json.Marshal(email)
if err != nil {
...
}
err = r.Redis.Publish(ctx, "email", emailJSON).Err()
if err != nil {
...
}
idk if using json is good practice.