@palmetto/pubsub 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +154 -0
  2. package/dist/bullmq/config.d.ts +21 -0
  3. package/dist/bullmq/config.js +2 -0
  4. package/dist/bullmq/connection.d.ts +2 -0
  5. package/dist/bullmq/connection.js +5 -0
  6. package/dist/bullmq/main.d.ts +6 -0
  7. package/dist/bullmq/main.js +21 -0
  8. package/dist/bullmq/publisher.d.ts +13 -0
  9. package/dist/bullmq/publisher.js +62 -0
  10. package/dist/bullmq/pubsub.d.ts +12 -0
  11. package/dist/bullmq/pubsub.js +35 -0
  12. package/dist/bullmq/subscriber.d.ts +27 -0
  13. package/dist/bullmq/subscriber.js +118 -0
  14. package/dist/errors.d.ts +17 -0
  15. package/dist/errors.js +37 -0
  16. package/dist/interfaces.d.ts +120 -0
  17. package/dist/interfaces.js +28 -0
  18. package/dist/lazy-load.d.ts +11 -0
  19. package/dist/lazy-load.js +79 -0
  20. package/dist/main.d.ts +6 -0
  21. package/dist/main.js +22 -0
  22. package/dist/publisher.d.ts +11 -0
  23. package/dist/publisher.js +87 -0
  24. package/dist/rabbitmq/config.d.ts +84 -0
  25. package/dist/rabbitmq/config.js +82 -0
  26. package/dist/rabbitmq/connection.d.ts +41 -0
  27. package/dist/rabbitmq/connection.js +140 -0
  28. package/dist/rabbitmq/main.d.ts +5 -0
  29. package/dist/rabbitmq/main.js +21 -0
  30. package/dist/rabbitmq/publisher.d.ts +29 -0
  31. package/dist/rabbitmq/publisher.js +98 -0
  32. package/dist/rabbitmq/pubsub.d.ts +15 -0
  33. package/dist/rabbitmq/pubsub.js +37 -0
  34. package/dist/rabbitmq/subscriber.d.ts +33 -0
  35. package/dist/rabbitmq/subscriber.js +197 -0
  36. package/dist/rabbitmq/utility.d.ts +6 -0
  37. package/dist/rabbitmq/utility.js +11 -0
  38. package/dist/subscriber.d.ts +28 -0
  39. package/dist/subscriber.js +140 -0
  40. package/package.json +54 -0
  41. package/src/bullmq/README.md +63 -0
  42. package/src/rabbitmq/README.md +184 -0
@@ -0,0 +1,63 @@
1
+ # @palmetto/pubsub
2
+
3
+ The BullMq transport provider for @palmetto/pubsub
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ yarn add @palmetto/pubsub bullmq zod
9
+ ```
10
+
11
+ ## Getting started
12
+
13
+ 1. Define your connection string
14
+
15
+ ```ts
16
+ const config: ConnectionOptions = {
17
+ host: "localhost",
18
+ port: 6379,
19
+ };
20
+ ```
21
+
22
+ 2. Create the publisher
23
+
24
+ ```ts
25
+ const publisher = new Publisher(console, [BullMqPublisher(config, console)]);
26
+ ```
27
+
28
+ 3. Create the subscriber
29
+
30
+ ```ts
31
+ const subscriber = new Subscriber(console, [
32
+ new BullMqSubscriber(config, console),
33
+ ]);
34
+ ```
35
+
36
+ 4. Create the queue configuration
37
+
38
+ ```ts
39
+ const queue: BullMqQueueConfiguration = {
40
+ name: "my-queue-name",
41
+ schema: MyModelSchema,
42
+ transport: BULLMQ_TRANSPORT,
43
+ job: "my-optional-job-name",
44
+ };
45
+ ```
46
+
47
+ 5. Publish a message
48
+
49
+ ```ts
50
+ const message: MyModel = {... };
51
+
52
+ await publisher.publish(config, message);
53
+ ```
54
+
55
+ 6. Subscribe to a queue
56
+
57
+ ```ts
58
+
59
+ subscriber.addSubscriber(queue, (message: MyModel, context: BullMqMessageContext) => {
60
+ ...
61
+ return MessageResult.Ok;
62
+ });
63
+ ```
@@ -0,0 +1,184 @@
1
+ # @palmetto/pubsub
2
+
3
+ The RabbitMq (AMQP) transport provider for @palmetto/pubsub
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ yarn add @palmetto/pubsub amqp-connection-manager amqplib zod
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ 1. Define your connection string
14
+
15
+ ```ts
16
+ const config: RabbitMqConnectionConfig = {
17
+ host: "amqp://guest:guest@localhost:5672/",
18
+ };
19
+ ```
20
+
21
+ 2. Create the connection
22
+
23
+ ```ts
24
+ const connection = new RabbitMqConnection(config, console);
25
+ ```
26
+
27
+ 3. Create the publisher
28
+
29
+ ```ts
30
+ const publisher = new Publisher(console, [
31
+ RabbitMqPublisher(connection, console),
32
+ ]);
33
+ ```
34
+
35
+ 4. Create the subscriber
36
+
37
+ ```ts
38
+ const subscriber = new Subscriber(console, [
39
+ new RabbitMqSubscriber(connection, console),
40
+ ]);
41
+ ```
42
+
43
+ 5. Create the queue configuration
44
+
45
+ ```ts
46
+ const queue: RabbitQueueExchangeConfiguration = {
47
+ name: "my-queue-name",
48
+ schema: MyModelSchema,
49
+ transport: RABBITMQ_TRANSPORT,
50
+ retries: 360,
51
+ retryDelay: 1_000,
52
+ };
53
+ ```
54
+
55
+ 6. Publish a message
56
+
57
+ ```ts
58
+ const message: MyModel = {... };
59
+
60
+ await publisher.publish(config, message);
61
+ ```
62
+
63
+ 7. Subscribe to a queue
64
+
65
+ ```ts
66
+ subscriber.addSubscriber(queue, (message: MyModel, context: RabbitMqMessageContext) => {
67
+ ...
68
+ return MessageResult.Ok;
69
+ });
70
+ ```
71
+
72
+ 8. Subscribe to the dead-letter queue if you want to re-process completely failed messages. Set the `queueType` to `"dead-letter"`
73
+
74
+ ```ts
75
+ const dlQueue = {
76
+ ...queue,
77
+ queueType: "dead-letter",
78
+ };
79
+
80
+ subscriber.addSubscriber(dlQueue, (message: MyModel, context: RabbitMqMessageContext) => {
81
+ ...
82
+ return MessageResult.Ok; // returning Ok will remove the message from the dlq
83
+ return MessageResult.Fail; // returning Fail will remove the message from the dlq
84
+ return MessageResult.Retry; // returning Retry will move the message to the retry queue and back into the normal queue processing
85
+ });
86
+ ```
87
+
88
+ ## Message failures
89
+
90
+ Message failures in RabbitMq subscribers are handled using special queues and exchanges. A retry queue is used to enable retry delays. A dead-letter queue is used to store messages that fail and run out of retries.
91
+
92
+ ### Retrying messages
93
+
94
+ These properties configure message retries:
95
+
96
+ - `retries` : specifies the number of retries after which the message is discarded. When this value is undefined, the message will retry forever.
97
+ - `retryDelay`: specifies the number of milliseconds between retries.
98
+
99
+ #### The retry queue
100
+
101
+ The retry queue is created using the queue name and ends with `.rlq`. The queue is configured with a dead-letter exchange that sends messages back to the original queue. A retry exchange with a default name of the queue ending with `.rlx` is bound to the retry queue. When a `retryDelay` is defined, the original message is re-published into the retry exchange with an `expiration` of the `retryDelay`. When the message is at the head of the retry queue and the expiration has elapsed, then RabbitMq removes the message from the queue and publishes it back to the original queue.
102
+
103
+ It's important to set a `retryDelay` that works for all messages of the queue. The `expiration` cannot be changed after starting. Every message must have the same expiration in order for retries to work correctly. Only the message at the head of the queue is removed at the expiration time. If there are more messages in the queue with earlier expirations, they will not be removed (re-tried) until they are at the head of the queue.
104
+
105
+ ### Failing messages
106
+
107
+ A dead-letter queue is created using the queue name and ends with `.dlq`. A dead-letter exchange is created using the queue name and ends with `.dlx`. Messages that fail are nack'ed to rabbit and are published to the main queue's dead-letter exchange.
108
+
109
+ Messages are sent to the dead-letter exchange when the handler returns `MessageResult.Fail` or when the message exceeds the number of `retries` configured.
110
+
111
+ ## Queue and Exchange Configuration
112
+
113
+ The simplest way to configure PubSub RabbitMq is to pass a single name for the queue and let the framework decide the rest.
114
+
115
+ ```ts
116
+ const config: RabbitQueueExchangeConfiguration = {
117
+ name: "my.queue",
118
+ transport: RABBITMQ_TRANSPORT,
119
+ schema: MyModelSchema,
120
+ };
121
+ ```
122
+
123
+ This configuration creates the following queues:
124
+
125
+ - `my.queue` the main queue which receives all messages published using the config
126
+ - dead-letter-exchange is set to `my.queue.dlx`
127
+ - `my.queue.dlq` the main queue's dead-letter queue where failed messages end up
128
+ - `my.queue.rtq` the main queue's retry queue where messages to be retried end up
129
+ - dead-letter-exchange is set to the main queue's exchange so that messages are retried
130
+
131
+ And these direct exchanges:
132
+
133
+ - `my.queue` the main exchange that is bound to the main queue
134
+ - `my.queue.dlx` the dead-letter exchange that receives failed messages from the main queue
135
+ - `my.queue.rtx` the retry exchange that receives messages to retry. it is bound to the retry queue
136
+
137
+ ### Topic exchanges
138
+
139
+ Topic exchanges provide the ability to use a single exchange to copy messages to multiple queues simultaneously. When subscribing to a topic exchange, you must also provide a subscriber name to include in the queue name. This ensures that there is a unique queue for each subscriber of the exchange.
140
+
141
+ ```ts
142
+ const config: RabbitQueueExchangeConfiguration = {
143
+ name: "my.queue",
144
+ transport: RABBITMQ_TRANSPORT,
145
+ schema: MyModelSchema,
146
+ exchangeType: "topic",
147
+ topicSubscriberName: "my-api-name",
148
+ retries: 100,
149
+ retryDelay: 10_000,
150
+ };
151
+ ```
152
+
153
+ This configuration would create a main queue called `my.queue.my-api-name`
154
+
155
+ ### Custom names
156
+
157
+ You can override all the queue, exchange names and routing keys for each `queueType`
158
+
159
+ ```ts
160
+ const config: RabbitQueueExchangeConfiguration = {
161
+ name: "my.queue",
162
+ transport: RABBITMQ_TRANSPORT,
163
+ schema: MyModelSchema,
164
+ overrides: {
165
+ names: {
166
+ default: {
167
+ queueName: "my.queue.name",
168
+ exchangeName: "some.exchange",
169
+ routingKey: "some.routing.key",
170
+ },
171
+ "dead-letter": {
172
+ queueName: "my.dead.letter.queue",
173
+ exchangeName: "my.dead.letter.exchange",
174
+ routingKey: "some.routing.key",
175
+ },
176
+ retry: {
177
+ queueName: "my.retry.queue",
178
+ exchangeName: "my.retry.exchange",
179
+ routingKey: "some.routing.key",
180
+ },
181
+ },
182
+ },
183
+ };
184
+ ```