"Blog time!"

Opentechiz blog

< Back

Redis-graphql-subscription and NodeJs Tutorial


Table of contents:

  1. Why do we need redis-graphql-subscription ?

  2. Compare between libraries implement graphql-subscription

  3. Setup configuration
  4. Basic example
  5. Next part, references

Require reading:

To learn how to use the core subscriptions feature, take a look at Amanda Liu’s subscriptions post:

https://blog.apollographql.com/graphql-subscriptions-in-apollo-client-9a2457f015fb

1, Why do we need redis-graphql-subscription ?

Redis-graphql-subscription is a library implement redis associate with graphql-subscription. This package implements the PubSubEngine Interface from the graphql-subscriptions package and also the new AsyncIterator interface. It allows you to connect your subscriptions manager to a Redis Pub Sub mechanism to support multiple subscription manager instances. Let’s look at a GraphQL subscription request:

subscription monkeysLocation($limit: Int!) {
   flyingMonkeysMoved($limit) {  
    location {  
      lat  
      lon   
      height   
    }  
   movementVector
 }
}

This request contains three parts:

Subscription operation name — this can be anything you like, and is mostly helpful for debugging:

subscription monkeysLocation($limit: Int!) {
  1. The root subscription field and parameters, often used for filtering publications:

flyingMonkeysMoved(limit: $limit) {
  1. The GraphQL selection set, which specifies which fields we want to get in the result:
location {  
  lat  
  lon   
  height   
}  
movementVector

All of this allows the client to get exactly the data that it needs.

That last part of the query is the actual difference between GraphQL subscriptions and the “regular” Pub Sub paradigm. This is also the part of GraphQL subscriptions that can easily become a bottleneck if you don’t pay attention, because GraphQL resolvers can run any async or sync job that you would like them to.

Future Optimizations

Right now the Subscriptions Manager runs the GraphQL query for each event and each subscriber. A pretty simple PR could implement shared execution for subscribers with the same query — as long as the response is not user-specific.

The Apollo team is also getting ready to implement GraphQL subscriptions in some of their own production apps, which will provide some more on-the-ground information about the performance of the system.

2, Compare between graphql-subscription libraries

GraphQL subscriptions is a simple npm package that lets you wire up GraphQL with a pubsub system (like Redis) to implement subscriptions in GraphQL. There are many pubsub implementation library

PubSub Implementations

It can be easily replaced with some other implementations of PubSubEngine interface. There are a couple of them out there:

3, Basic setup

STEP 0: Download and install redis-server on your local machine

  • Follow the link to https://redis.io/download to download the suitable version for your OS

  • After installing redis, you can test it with a few steps

  • Start the redis server by navigate to your redis directory by command line

cd  ~/redis-5.x.x src/redis-server
  • Secondly, You can interact with Redis using the built-in client:

src/redis-cli

then let’s try with “ping” , the output should be “pong”

  • With very basic usage, you can interact with redis database by using these command

$ src/redis-cli 
redis> set foo bar
OK
redis> get foo "bar"

STEP 1 install graphql-redis-subscription for your project

  1. Follow the link https://github.com/davidyaha/graphql-redis-subscriptions

  2. Make sure you have already installed NodeJs and NPM on your local machine

  3. Install redis-subscriptions by using npm

Install redis-subscriptions by using npm
  1. As a peer-dependencies, graphql-subscription must be installed too

npm install graphql-subscriptions
  1. In this tutorial we used one more thing to easily setup the redis with NodeJs. Go to https://github.com/luin/ioredis and install ioredis. The setup is quite simple that you can follow the documentation. Including it to this article may be too long and unnecessary.

STEP 2 Using redis graphql subscriptions on your project by adding this code

import * as Redis from 'ioredis';

const options = {
  host: REDIS_DOMAIN_NAME,
  port: PORT_NUMBER,
  retry_strategy: options => {
    // reconnect after
    return Math.max(options.attempt * 100, 3000);
  }
};

const pubsub = new RedisPubSub({
  ...,
  publisher: new Redis(options),
  subscriber: new Redis(options)
});

If you didn’t pass the options to Redis, it will automatically set the host to http://localhost and the port to 6379

STEP 3: Run your subscription and check the terminal

In the command line, enter

redis-cli monitorOK

Your output subscription should arrive here whenever you publish a subscription

Below is simple graphql subscription example

Define your GraphQL schema with a Subscription type:

schema {
  query: Query
  mutation: Mutation
  subscription: Subscription
}

type Subscription {
    somethingChanged: Result
}

type Result {
    id: String
}

Now, let's create a simple RedisPubSub instance:

import { RedisPubSub } from 'graphql-redis-subscriptions';
const pubsub = new RedisPubSub();
const SOMETHING_CHANGED_TOPIC = 'something_changed';

export const resolvers = {
  Subscription: {
    somethingChanged: {
      subscribe: () => pubsub.asyncIterator(SOMETHING_CHANGED_TOPIC),
    },
  },
}

Subscriptions resolvers are not a function, but an object with subscribe method, that returns AsyncIterable.

Calling the method asyncIterator of the RedisPubSub instance will send redis a SUBSCRIBE message to the topic provided and will return an AsyncIterator binded to the RedisPubSub instance and listens to any event published on that topic. Now, the GraphQL engine knows that somethingChanged is a subscription, and every time we will use pubsub.publish over this topic, the RedisPubSub will PUBLISH the event over redis to all other subscribed instances and those in their turn will emit the event to GraphQL using the next callback given by the GraphQL engine.

pubsub.publish(SOMETHING_CHANGED_TOPIC, { somethingChanged: { id: "123" }});

Dynamically create a topic based on subscription args passed on the query:

export const resolvers = {
  Subscription: {
    somethingChanged: {
      subscribe: (_, args) => pubsub.asyncIterator(`${SOMETHING_CHANGED_TOPIC}.${args.relevantId}`),
    },
  },
}

Using both arguments and payload to filter events

import { withFilter } from 'graphql-subscriptions';

export const resolvers = {
  Subscription: {
    somethingChanged: {
      subscribe: withFilter(
        (_, args) => pubsub.asyncIterator(`${SOMETHING_CHANGED_TOPIC}.${args.relevantId}`),
        (payload, variables) => payload.somethingChanged.id === variables.relevantId,
      ),
    },
  },
}

References

We are done now, let's try to publish a subscription and check your command line with redis-cll monitor. If you subscription came, Congratulation !!!

In the next part, we will walk through graphql-google-subscription This article was written by @Harry and reference to these following:

https://blog.apollographql.com/graphql-subscriptions-with-redis-pub-sub-f636fc84a0c4

https://github.com/davidyaha/graphql-redis-subscriptions

https://redis.io/

Thanks for reading !