Skip to content

Commit 5890cc4

Browse files
committed
redis pubsub
1 parent 6015a48 commit 5890cc4

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

packages/web/docs/src/content/gateway/subscriptions.mdx

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,3 +788,138 @@ export const network = Network.create(fetchQuery, subscribe)
788788
</Tabs.Tab>
789789

790790
</Tabs>
791+
792+
## PubSub
793+
794+
Hive Gateway internally uses a PubSub system to handle subscriptions. By default, an in-memory
795+
PubSub engine is used when detecting subscriptions.
796+
797+
You can implement your own PubSub engine by implementing the `PubSub` interface from the
798+
`@graphql-hive/pubsub` package, which looks like this:
799+
800+
```ts
801+
export type TopicDataMap = { [topic: string]: any /* data */ }
802+
803+
export type PubSubListener<Data extends TopicDataMap, Topic extends keyof Data> = (
804+
data: Data[Topic]
805+
) => void
806+
807+
type MaybePromise<T> = T | Promise<T>
808+
809+
export interface PubSub<M extends TopicDataMap = TopicDataMap> {
810+
/**
811+
* Publish {@link data} for a {@link topic}.
812+
* @returns `void` or a `Promise` that resolves when the data has been successfully published
813+
*/
814+
publish<Topic extends keyof M>(topic: Topic, data: M[Topic]): MaybePromise<void>
815+
/**
816+
* A distinct list of all topics that are currently subscribed to.
817+
* Can be a promise to accomodate distributed systems where subscribers exist on other
818+
* locations and we need to know about all of them.
819+
*/
820+
subscribedTopics(): MaybePromise<Iterable<keyof M>>
821+
/**
822+
* Subscribe and listen to a {@link topic} receiving its data.
823+
*
824+
* If the {@link listener} is provided, it will be called whenever data is emitted for the {@link topic},
825+
*
826+
* @returns an unsubscribe function or a `Promise<unsubscribe function>` that resolves when the subscription is successfully established. the unsubscribe function returns `void` or a `Promise` that resolves on successful unsubscribe and subscription cleanup
827+
*
828+
* If the {@link listener} is not provided,
829+
*
830+
* @returns an `AsyncIterable` that yields data for the given {@link topic}
831+
*/
832+
subscribe<Topic extends keyof M>(topic: Topic): AsyncIterable<M[Topic]>
833+
subscribe<Topic extends keyof M>(
834+
topic: Topic,
835+
listener: PubSubListener<M, Topic>
836+
): MaybePromise<() => MaybePromise<void>>
837+
/**
838+
* Closes active subscriptions and disposes of all resources. Publishing and subscribing after disposal
839+
* is not possible and will throw an error if attempted.
840+
*/
841+
dispose(): MaybePromise<void>
842+
/** @see {@link dispose} */
843+
[Symbol.asyncDispose](): Promise<void>
844+
}
845+
```
846+
847+
The `@grpahql-hive/pubsub` package also provides a few built-in PubSub engines, at the moment an
848+
in-memory engine and a Redis-based engine.
849+
850+
### In-Memory PubSub
851+
852+
The in-memory PubSub engine is the default engine used when subscriptions are detected. It can also
853+
be used explicitly by setting it in the configuration.
854+
855+
```ts filename="gateway.config.ts"
856+
import { defineConfig } from '@graphql-hive/gateway'
857+
import { MemPubSub } from '@graphql-hive/pubsub'
858+
// or from the Hive Gateway package
859+
import { MemPubSub } from '@graphql-hive/gateway'
860+
861+
export const gatewayConfig = defineConfig({
862+
supergraph: 'supergraph.graphql',
863+
pubsub: new MemPubSub()
864+
})
865+
```
866+
867+
### Redis PubSub
868+
869+
For more advanced use-cases, such as running multiple instances of Hive Gateway, you can use the
870+
Redis-based PubSub engine we offer out of the box.
871+
872+
In case you have distributed instances of Hive Gateway, using a distributed PubSub engine is
873+
required to make sure all instances are aware of all active subscriptions and can publish events to
874+
the correct subscribers.
875+
876+
For example, when using the webhooks transport for subscriptions, the subgraph will send events to
877+
only one instance of Hive Gateway. If that instance doesn't have any active subscription for the
878+
topic, the event will be lost. Using a distributed PubSub engine solves this problem.
879+
880+
Redis PubSub does not come with Hive Gateway, you have to install the package and the Redis PubSub
881+
peer dependency of `ioredis` which you need to install first:
882+
883+
```sh npm2yarn
884+
npm i @graphql-hive/pubsub ioredis
885+
```
886+
887+
```ts filename="gateway.config.ts"
888+
import Redis from 'ioredis'
889+
import { defineConfig } from '@graphql-hive/gateway'
890+
import { RedisPubSub } from '@graphql-hive/pubsub/redis'
891+
892+
/**
893+
* When a Redis connection enters "subscriber mode" (after calling SUBSCRIBE), it can only execute
894+
* subscriber commands (SUBSCRIBE, UNSUBSCRIBE, etc.). Meaning, it cannot execute other commands like PUBLISH.
895+
* To avoid this, we use two separate Redis clients: one for publishing and one for subscribing.
896+
*/
897+
const pub = new Redis()
898+
const sub = new Redis()
899+
900+
export const gatewayConfig = defineConfig({
901+
webhooks: true,
902+
pubsub: new RedisPubSub(
903+
{ pub, sub },
904+
{
905+
// we make sure to use the same prefix for all gateways to share the same channels and pubsub
906+
// meaning, all gateways using this channel prefix will receive and publish to the same topics
907+
channelPrefix: 'my-shared-gateways'
908+
}
909+
)
910+
})
911+
```
912+
913+
Now, with this setup, any instance of Hive Gateway using the same `channelPrefix` will be able to
914+
share the same subscriptions.
915+
916+
<Callout>
917+
918+
Note that this works only if you have subgraphs that publish subscriptions to Hive Gateway's webhook
919+
to the same pubsub topic
920+
([see documentation on using webhooks to handle subscriptions](https://the-guild.dev/graphql/mesh/v1/subscriptions-webhooks)).
921+
922+
You should also take a look at the E2E test serving as an example of
923+
[how distributed subscriptions would work with multiple Hive Gateway instances](https://github.com/graphql-hive/gateway/tree/main/e2e/distributed-subscriptions-webhooks).
924+
925+
</Callout>

0 commit comments

Comments
 (0)