Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how do subscriptions work for multiple load balanced websocker servers? #846

Closed
bjm88 opened this issue Aug 28, 2019 · 4 comments
Closed
Labels

Comments

@bjm88
Copy link

bjm88 commented Aug 28, 2019

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!

@felipemfp
Copy link

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())
}

@stale
Copy link

stale bot commented Nov 4, 2019

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.

@stale stale bot added the stale label Nov 4, 2019
@stale stale bot closed this as completed Nov 11, 2019
@PunkHaz4rd
Copy link

I'm getting undefined: redigosrv.DefaultRedigoService
Any update since then ?

@scorpionknifes
Copy link

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants