1 | # @rxdi/graphql-rabbitmq-subscriptions
|
2 | Forked from [graphql-rabbitmq-subscriptions](https://github.com/cdmbase/graphql-rabbitmq-subscriptions)
|
3 |
|
4 | This package implements the PusSubEngine Interface from the graphql-subscriptions package.
|
5 | It allows you to connect your subscriptions manger to a rabbitmq Pub Sub mechanism to support
|
6 | multiple subscription manager instances.
|
7 |
|
8 | This package is copied from [graphql-redis-subscriptions](https://github.com/davidyaha/graphql-redis-subscriptions) originally and modified to work with RabbitMQ.
|
9 |
|
10 | ## Basic Usage
|
11 |
|
12 | ```javascript
|
13 | import { AmqpPubSub } from 'graphql-rabbitmq-subscriptions';
|
14 | const logger = <log function>;
|
15 | const pubsub = new AmqpPubSub({logger});
|
16 | const subscriptionManager = new SubscriptionManager({
|
17 | schema,
|
18 | pubsub,
|
19 | setupFunctions: {},
|
20 | });
|
21 | ```
|
22 |
|
23 | ## Logging example
|
24 |
|
25 | The `logger` need to be implementation of `bunyan`. You can use following example logger.
|
26 |
|
27 | ```javascript
|
28 | import {ConsoleLogger,IConsoleLoggerSettings} from "@cdm-logger/server";
|
29 | import * as Logger from "bunyan";
|
30 |
|
31 | const settings: IConsoleLoggerSettings = {
|
32 | level: "info", // Optional: default 'info' ('trace'|'info'|'debug'|'warn'|'error'|'fatal')
|
33 | mode: "short" // Optional: default 'short' ('short'|'long'|'dev'|'raw')
|
34 | }
|
35 |
|
36 | const logger: Logger = ConsoleLogger.create("<app name>", settings);
|
37 | ```
|
38 |
|
39 | Sample Logging trace file
|
40 | ```
|
41 | [15:01:16.046Z] TRACE integration-test: trying to subscribe to queue 'testSubscription' (child=amqp-pubsub, class=AmqpPubSub)
|
42 | [15:01:16.050Z] DEBUG integration-test: connecting to amqp://127.0.0.1:5672 (child=rabbitmq-pub-sub, class=RabbitMqConnectionFactory)
|
43 | [15:01:16.109Z] TRACE integration-test: got channel for queue 'testSubscription' (child=rabbitmq-pub-sub, class=RabbitMqConsumer)
|
44 | [15:01:16.110Z] TRACE integration-test: setup '{"name":"testSubscription","dlq":"","dlx":"testSubscription.DLQ.Exchange"}' (child=rabbitmq-pub-sub, class=RabbitMqConsumer)
|
45 | [15:01:16.117Z] DEBUG integration-test: queue name generated for subscription queue '(testSubscription)' is '(amq.gen-0Nan220vcDjNVmnnXZOZxg)' (child=rabbitmq-pub-sub, class=RabbitMqConsumer)
|
46 | [15:01:16.117Z] TRACE integration-test: subscribing to queue 'testSubscription' (child=rabbitmq-pub-sub, class=RabbitMqConsumer)
|
47 | [15:01:16.119Z] TRACE integration-test: subscribed to queue 'testSubscription' (amq.ctag-nZJSNBvCUl2V_RGYF5ie5w) (child=rabbitmq-pub-sub, class=RabbitMqConsumer)
|
48 | [15:01:16.119Z] TRACE integration-test: publishing for queue 'testSubscription' ("good") (child=amqp-pubsub, class=AmqpPubSub)
|
49 | [15:01:16.120Z] DEBUG integration-test: connecting to amqp://127.0.0.1:5672 (child=rabbitmq-pub-sub, class=RabbitMqConnectionFactory)
|
50 | [15:01:16.126Z] TRACE integration-test: got channel for exchange 'testSubscription.DLQ.Exchange' (child=rabbitmq-pub-sub, class=RabbitMqPublisher)
|
51 | [15:01:16.127Z] TRACE integration-test: setup '{"name":"testSubscription","dlq":"","dlx":"testSubscription.DLQ.Exchange"}' (child=rabbitmq-pub-sub, class=RabbitMqPublisher)
|
52 | [15:01:16.130Z] TRACE integration-test: message sent to exchange 'testSubscription.DLQ.Exchange' ("good") (child=rabbitmq-pub-sub, class=RabbitMqPublisher)
|
53 | [15:01:16.132Z] TRACE integration-test: message arrived from queue 'testSubscription' ("good") (child=rabbitmq-pub-sub, class=RabbitMqConsumer)
|
54 | [15:01:16.133Z] TRACE integration-test: sending message to subscriber callback function '("good")' (child=amqp-pubsub, class=AmqpPubSub)
|
55 | [15:01:16.137Z] TRACE integration-test: disposing subscriber to queue 'testSubscription' (amq.ctag-nZJSNBvCUl2V_RGYF5ie5w) (child=rabbitmq-pub-sub, class=RabbitMqConsumer)
|
56 | [15:01:16.137Z] TRACE integration-test: list of subscriptions still available '({})' (child=amqp-pubsub, class=AmqpPubSub)
|
57 | [15:01:16.138Z] TRACE integration-test: message processed from queue 'testSubscription' ("good") (child=rabbitmq-pub-sub, class=RabbitMqConsumer)
|
58 | ```
|
59 | More details about [@cdm-logger/server](https://github.com/cdmbase/cdm-logger)
|
60 |
|
61 | ## Using Trigger Transform
|
62 |
|
63 | Recently, graphql-subscriptions package added a way to pass in options to each call of subscribe.
|
64 | Those options are constructed via the setupFunctions object you provide the Subscription Manager constructor.
|
65 | The reason for graphql-subscriptions to add that feature is to allow pub sub engines a way to reduce their subscription set using the best method of said engine.
|
66 | For example, meteor's live query could use mongo selector with arguments passed from the subscription like the subscribed entity id.
|
67 |
|
68 | This is only the standard but I would like to present an example of creating a specific subscription using the channel options feature.
|
69 |
|
70 | First I create a simple and generic trigger transform
|
71 | ```javascript
|
72 | const triggerTransform = (trigger, {path}) => [trigger, ...path].join('.');
|
73 | ```
|
74 |
|
75 | Then I pass it to the `AmqpPubSub` constructor.
|
76 | ```javascript
|
77 | const pubsub = new AmqpPubSub({
|
78 | triggerTransform,
|
79 | });
|
80 | ```
|
81 | Lastly, I provide a setupFunction for `commentsAdded` subscription field.
|
82 | It specifies one trigger called `comments.added` and it is called with the channelOptions object that holds `repoName` path fragment.
|
83 | ```javascript
|
84 | const subscriptionManager = new SubscriptionManager({
|
85 | schema,
|
86 | setupFunctions: {
|
87 | commentsAdded: (options, {repoName}) => ({
|
88 | 'comments.added': {
|
89 | channelOptions: {path: [repoName]},
|
90 | },
|
91 | }),
|
92 | },
|
93 | pubsub,
|
94 | });
|
95 | ```
|
96 |
|
97 | When I call `subscribe` like this:
|
98 | ```javascript
|
99 | const query = `
|
100 | subscription X($repoName: String!) {
|
101 | comments.added(repoName: $repoName)
|
102 | }
|
103 | `;
|
104 | const variables = {repoName: 'graphql-rabbitmq-subscriptions'};
|
105 | subscriptionManager.subscribe({query, operationName: 'X', variables, callback});
|
106 | ```
|
107 |
|
108 | The subscription string that RabbitMQ will receive will be `comments.added.graphql-rabbitmq-subscriptions`.
|
109 | This subscription string is much more specific and means the the filtering required for this type of subscription is not needed anymore.
|
110 | This is one step towards lifting the load off of the graphql api server regarding subscriptions.
|
111 |
|
112 | ## Passing rabbitmq options object
|
113 |
|
114 | The basic usage is great for development and you will be able to connect to a rabbitmq server running on your system seamlessly.
|
115 | But for any production usage you should probably pass in a rabbitmq options object
|
116 |
|
117 | ```javascript
|
118 | import { AmqpPubSub } from 'graphql-rabbitmq-subscriptions';
|
119 |
|
120 | const pubsub = new AmqpPubSub({
|
121 | config: {
|
122 | host: RABBITMQ_DOMAIN_NAME,
|
123 | port: PORT_NUMBER,
|
124 | },
|
125 | logger,
|
126 | });
|
127 | ```
|