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

Support for NATS as a subscriptions backplane #5441

Merged

Conversation

oising
Copy link
Contributor

@oising oising commented Sep 26, 2022

NATS GraphQL Subscriptions backplane for HotChocolate

What is NATS?

NATS is a simple, secure and high performance open source messaging system for cloud native applications, IoT messaging, and microservices architectures. It offers services for both asynchronous communication and streaming data.

Why do I need NATS for my GraphQL Subscriptions?

If you scale your HotChocolate servers beyond a single node, some of your GraphQL Subscriptions will be handled by different servers. The subscriber may receive the subscription results on a different server than the publisher. In order to make this work, you need a backplane. Another example of a backplane is the Redis backplane that is included in HotChocolate. The Redis backplane is a good choice if you want to reuse some of your existing infrastructure. However, if you want to avoid the overhead of a Redis server, you can use the NATS backplane.

The NATS backplane is a simple and lightweight alternative to the Redis backplane. It is also typically faster than the Redis backplane, and cheaper, as you can run it on lightweight hardware, virtual or not, and scale it horizontally. The Publish/Subscribe pattern does not require a lot of memory, and Redis typically scales in a vertical fashion, adding more memory to a single server. NATS scales horizontally, adding more servers to the cluster.

How do I use the NATS backplane?

You can start with a single node of NATS and see where you need to go from there. You can also start with a cluster of NATS servers and scale it. The NATS client uses a technique called client-side load balancing to distribute the load across the cluster. The NATS client will automatically discover the cluster and choose the correct server to publish to or subscribe from, based on a hash of the subject. The NATS client will also automatically reconnect to the cluster if a server goes down.

You do not need to enable persistence in the NATS server (JetStream) for Publish/Subscribe to function.

using AlterNats;
using HotChocolate.Execution;
using HotChocolate.Subscriptions;

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddNats(poolSize: 1, opts => opts with
    {
        Url = "nats://localhost:4222",
        // Optional serializer (defaults to System.Text.Json)
        Serializer = new MessagePackNatsSerializer()
    })
    .AddNatsSubscriptions()
    .AddGraphQLServer()
    .AddMutationConventions()
    .AddQueryType<Query>()
    .AddMutationType<Mutation>()
    .AddSubscriptionType<Subscription>();

var app = builder.Build();

app.UseWebSockets();
app.UseRouting();
app.UseEndpoints(ep =>
{
    ep.MapGraphQL();
});

await app.RunAsync();

NOTE:
You need to target net6.0 or higher to use this provider, as the NATS client dependency is not available for net5.0 or lower.

Multiple Environment Support

If you wish to share a NATS instance/cluster with multiple, distinct GraphQL servers, you must provide a unique subject prefix for this instance, e.g. an environment string like "dev01". This prefix is passed in the initial setup, like so: AddNatsSubscription(prefix: "dev01"). All servers with the same prefix will be part of the same publish/subscribe group, and will receive all messages. The prefix will be prepended to all NATS subjects with the "." subject token separator, and as such can be monitored with the NATS CLI using the > operator:

./nats -s localhost:4222 subscribe "dev01.>"

If you do not provide a prefix, the server will use the default prefix of "graphql". Only a-z, A-Z and 0-9 characters are permitted. The prefix is case sensitive.

Technical Information about NATS

NATS has a nice command line interface which you can use to monitor the cluster. You can also use the NATS dashboard to monitor the cluster.

NATS PubSub overview using NATS CLI

https://www.youtube.com/watch?v=jLTVhP08Tq0

@michaelstaib
Copy link
Member

Is there a docker image with this available?

@michaelstaib
Copy link
Member

https://hub.docker.com/_/nats

@michaelstaib
Copy link
Member

We need to create a squadron package for this so we can test this thing.

@oising
Copy link
Contributor Author

oising commented Sep 27, 2022

We need to create a squadron package for this so we can test this thing.

Yeah, I looked to see what Squadron was, and it seems there is no OOTB NATS package - if this is something that is expected to be written by us* (i.e. could be me?) then let me know where I could start.

@oising
Copy link
Contributor Author

oising commented Oct 3, 2022

Waiting on SwissLife-OSS/squadron#123

update: Squadron.Nats released a preview, so no longer blocked

@oising oising marked this pull request as draft October 5, 2022 19:57
@oising
Copy link
Contributor Author

oising commented Oct 5, 2022

Uncovered a race condition in my NatsPubSub implementation -- marking as draft until squadron tests can prove otherwise

@oising oising marked this pull request as ready for review October 5, 2022 21:11
@oising
Copy link
Contributor Author

oising commented Oct 5, 2022

@PascalSenn @michaelstaib - ready to review now, but there's still an issue in core with net7-rc1 (src/HotChocolate/Language/src/Language.Utf8/Utf8Helper.cs won't compile due to ref local issue)

  • added new NATS squadron package
  • added integration test with full subscribe/publish loop

@michaelstaib
Copy link
Member

Let me check

@michaelstaib michaelstaib merged commit 544688d into ChilliCream:main Nov 25, 2022
@oising oising deleted the feature/subscriptions-natsio-oising branch November 26, 2022 00:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants