@venizia/ignis-docs 0.2.0 → 0.2.1-1

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 (174) hide show
  1. package/README.md +14 -14
  2. package/content/best-practices/api-usage-examples.md +39 -19
  3. package/content/best-practices/architectural-patterns.md +24 -13
  4. package/content/best-practices/architecture-decisions.md +29 -16
  5. package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
  6. package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
  7. package/content/best-practices/code-style-standards/control-flow.md +33 -1
  8. package/content/best-practices/code-style-standards/documentation.md +28 -8
  9. package/content/best-practices/code-style-standards/function-patterns.md +15 -4
  10. package/content/best-practices/code-style-standards/index.md +7 -2
  11. package/content/best-practices/code-style-standards/naming-conventions.md +27 -3
  12. package/content/best-practices/code-style-standards/route-definitions.md +9 -5
  13. package/content/best-practices/code-style-standards/tooling.md +14 -1
  14. package/content/best-practices/code-style-standards/type-safety.md +39 -6
  15. package/content/best-practices/common-pitfalls.md +59 -35
  16. package/content/best-practices/contribution-workflow.md +8 -4
  17. package/content/best-practices/data-modeling.md +78 -62
  18. package/content/best-practices/deployment-strategies.md +56 -19
  19. package/content/best-practices/error-handling.md +247 -153
  20. package/content/best-practices/index.md +6 -0
  21. package/content/best-practices/performance-optimization.md +26 -13
  22. package/content/best-practices/security-guidelines.md +35 -9
  23. package/content/best-practices/testing-strategies.md +7 -2
  24. package/content/best-practices/troubleshooting-tips.md +27 -17
  25. package/content/extensions/components/api-reference.md +109 -323
  26. package/content/extensions/components/authentication/api.md +489 -602
  27. package/content/extensions/components/authentication/errors.md +135 -498
  28. package/content/extensions/components/authentication/index.md +89 -801
  29. package/content/extensions/components/authentication/usage.md +231 -955
  30. package/content/extensions/components/authorization/api.md +991 -644
  31. package/content/extensions/components/authorization/errors.md +204 -208
  32. package/content/extensions/components/authorization/getting-started.md +227 -0
  33. package/content/extensions/components/authorization/index.md +88 -795
  34. package/content/extensions/components/authorization/usage.md +219 -528
  35. package/content/extensions/components/health-check.md +77 -243
  36. package/content/extensions/components/index.md +24 -90
  37. package/content/extensions/components/mail/api.md +553 -285
  38. package/content/extensions/components/mail/errors.md +76 -62
  39. package/content/extensions/components/mail/index.md +111 -463
  40. package/content/extensions/components/mail/usage.md +139 -173
  41. package/content/extensions/components/request-tracker.md +70 -173
  42. package/content/extensions/components/socket-io/api.md +462 -785
  43. package/content/extensions/components/socket-io/errors.md +49 -51
  44. package/content/extensions/components/socket-io/index.md +69 -372
  45. package/content/extensions/components/socket-io/usage.md +212 -105
  46. package/content/extensions/components/static-asset/api.md +461 -141
  47. package/content/extensions/components/static-asset/errors.md +121 -53
  48. package/content/extensions/components/static-asset/index.md +84 -606
  49. package/content/extensions/components/static-asset/usage.md +184 -299
  50. package/content/extensions/components/template/index.md +3 -3
  51. package/content/extensions/components/websocket/api.md +311 -404
  52. package/content/extensions/components/websocket/errors.md +47 -56
  53. package/content/extensions/components/websocket/index.md +75 -407
  54. package/content/extensions/components/websocket/usage.md +120 -338
  55. package/content/extensions/helpers/cron/index.md +52 -160
  56. package/content/extensions/helpers/crypto/index.md +67 -480
  57. package/content/extensions/helpers/crypto/reference.md +528 -0
  58. package/content/extensions/helpers/env/index.md +64 -178
  59. package/content/extensions/helpers/error/index.md +286 -196
  60. package/content/extensions/helpers/index.md +61 -47
  61. package/content/extensions/helpers/inversion/index.md +76 -550
  62. package/content/extensions/helpers/inversion/reference.md +530 -0
  63. package/content/extensions/helpers/kafka/admin.md +23 -3
  64. package/content/extensions/helpers/kafka/compile-binary.md +83 -52
  65. package/content/extensions/helpers/kafka/consumer.md +65 -28
  66. package/content/extensions/helpers/kafka/examples.md +46 -253
  67. package/content/extensions/helpers/kafka/index.md +55 -617
  68. package/content/extensions/helpers/kafka/producer.md +156 -22
  69. package/content/extensions/helpers/kafka/schema-registry.md +59 -79
  70. package/content/extensions/helpers/logger/hf-logger.md +220 -0
  71. package/content/extensions/helpers/logger/index.md +78 -552
  72. package/content/extensions/helpers/logger/pino.md +105 -0
  73. package/content/extensions/helpers/logger/reference.md +937 -0
  74. package/content/extensions/helpers/network/api.md +276 -195
  75. package/content/extensions/helpers/network/index.md +87 -524
  76. package/content/extensions/helpers/queue/index.md +80 -897
  77. package/content/extensions/helpers/queue/reference.md +494 -0
  78. package/content/extensions/helpers/redis/index.md +86 -640
  79. package/content/extensions/helpers/redis/reference.md +784 -0
  80. package/content/extensions/helpers/secrets/index.md +136 -0
  81. package/content/extensions/helpers/socket-io/api.md +325 -204
  82. package/content/extensions/helpers/socket-io/index.md +79 -429
  83. package/content/extensions/helpers/storage/api.md +584 -464
  84. package/content/extensions/helpers/storage/index.md +80 -573
  85. package/content/extensions/helpers/types/index.md +75 -495
  86. package/content/extensions/helpers/types/reference.md +689 -0
  87. package/content/extensions/helpers/uid/index.md +176 -189
  88. package/content/extensions/helpers/websocket/api.md +366 -214
  89. package/content/extensions/helpers/websocket/index.md +68 -503
  90. package/content/extensions/helpers/worker-thread/index.md +62 -396
  91. package/content/extensions/helpers/worker-thread/reference.md +428 -0
  92. package/content/extensions/index.md +38 -39
  93. package/content/extensions/src-details/mcp-server.md +96 -548
  94. package/content/guides/core-concepts/persistent/datasources.md +2 -2
  95. package/content/guides/core-concepts/persistent/index.md +5 -1
  96. package/content/guides/core-concepts/persistent/models.md +1 -1
  97. package/content/guides/core-concepts/persistent/pglite.md +218 -0
  98. package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
  99. package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
  100. package/content/guides/core-concepts/persistent/search-typesense.md +28 -16
  101. package/content/guides/core-concepts/persistent/sqlite.md +296 -0
  102. package/content/guides/core-concepts/persistent/transactions.md +12 -11
  103. package/content/guides/core-concepts/secrets-vault.md +177 -0
  104. package/content/guides/core-concepts/services.md +1 -1
  105. package/content/guides/get-started/5-minute-quickstart.md +59 -206
  106. package/content/guides/get-started/philosophy.md +135 -670
  107. package/content/guides/get-started/setup.md +53 -74
  108. package/content/guides/migrations/redis-helpers-migration.md +5 -4
  109. package/content/guides/migrations/scoped-rbac-migration.md +5 -5
  110. package/content/guides/migrations/unified-connectors-migration.md +8 -7
  111. package/content/guides/tutorials/ecommerce-api.md +3 -8
  112. package/content/guides/tutorials/realtime-chat.md +1 -1
  113. package/content/references/base/application.md +64 -22
  114. package/content/references/base/components.md +3 -3
  115. package/content/references/base/connectors.md +79 -136
  116. package/content/references/base/controllers.md +12 -12
  117. package/content/references/base/datasources-reference.md +600 -0
  118. package/content/references/base/datasources.md +84 -444
  119. package/content/references/base/dependency-injection.md +25 -46
  120. package/content/references/base/filter-system/application-usage.md +95 -123
  121. package/content/references/base/filter-system/array-operators.md +33 -43
  122. package/content/references/base/filter-system/comparison-operators.md +55 -63
  123. package/content/references/base/filter-system/default-filter.md +144 -350
  124. package/content/references/base/filter-system/fields-order-pagination.md +116 -148
  125. package/content/references/base/filter-system/index.md +114 -253
  126. package/content/references/base/filter-system/json-filtering.md +52 -181
  127. package/content/references/base/filter-system/list-operators.md +28 -44
  128. package/content/references/base/filter-system/logical-operators.md +69 -114
  129. package/content/references/base/filter-system/null-operators.md +41 -98
  130. package/content/references/base/filter-system/pattern-matching.md +48 -51
  131. package/content/references/base/filter-system/quick-reference.md +93 -196
  132. package/content/references/base/filter-system/range-operators.md +22 -38
  133. package/content/references/base/filter-system/tips.md +70 -133
  134. package/content/references/base/filter-system/use-cases.md +173 -232
  135. package/content/references/base/grpc-controllers.md +53 -17
  136. package/content/references/base/index.md +5 -3
  137. package/content/references/base/middlewares.md +43 -28
  138. package/content/references/base/models-reference.md +886 -0
  139. package/content/references/base/models.md +81 -1452
  140. package/content/references/base/providers.md +8 -8
  141. package/content/references/base/repositories/advanced.md +281 -419
  142. package/content/references/base/repositories/index.md +84 -644
  143. package/content/references/base/repositories/mixins.md +25 -21
  144. package/content/references/base/repositories/relations.md +194 -375
  145. package/content/references/base/repositories/soft-deletable.md +67 -55
  146. package/content/references/base/secrets.md +267 -0
  147. package/content/references/base/services.md +8 -6
  148. package/content/references/configuration/environment-variables.md +73 -21
  149. package/content/references/configuration/index.md +51 -31
  150. package/content/references/index.md +1 -1
  151. package/content/references/quick-reference.md +3 -16
  152. package/content/references/utilities/crypto.md +35 -76
  153. package/content/references/utilities/date.md +33 -73
  154. package/content/references/utilities/duration.md +85 -0
  155. package/content/references/utilities/index.md +6 -2
  156. package/content/references/utilities/jsx-reference.md +298 -0
  157. package/content/references/utilities/jsx.md +82 -525
  158. package/content/references/utilities/module.md +81 -61
  159. package/content/references/utilities/parse.md +34 -64
  160. package/content/references/utilities/performance.md +33 -58
  161. package/content/references/utilities/promise.md +28 -62
  162. package/content/references/utilities/request.md +58 -218
  163. package/content/references/utilities/retry.md +139 -0
  164. package/content/references/utilities/schema.md +43 -137
  165. package/content/references/utilities/statuses-reference.md +361 -0
  166. package/content/references/utilities/statuses.md +63 -667
  167. package/dist/mcp-server/index.js +0 -0
  168. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
  169. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
  170. package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
  171. package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
  172. package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
  173. package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
  174. package/package.json +24 -23
@@ -1,982 +1,165 @@
1
- # Queue
2
-
3
- Message queuing and asynchronous task management with BullMQ, Kafka, MQTT, and in-memory solutions.
4
-
5
- ## Quick Reference
1
+ ---
2
+ title: Queue
3
+ description: Redis-backed job processing with BullMQ, a single-process in-memory queue, and MQTT pub/sub - three queueing backends behind one helper family
4
+ difficulty: intermediate
5
+ ---
6
6
 
7
- | Class | Extends | Peer Dependency | Use Case |
8
- |-------|---------|-----------------|----------|
9
- | **BullMQHelper** | `BaseHelper` | `bullmq` (^5.70.0) | Redis-backed job queue -- background processing, task scheduling |
10
- | **KafkaProducerHelper** | `BaseKafkaHelper` | `@platformatic/kafka` (^1.30.0) | Kafka message producer with transaction support |
11
- | **KafkaConsumerHelper** | `BaseKafkaHelper` | `@platformatic/kafka` (^1.30.0) | Kafka message consumer with lag monitoring |
12
- | **KafkaAdminHelper** | `BaseKafkaHelper` | `@platformatic/kafka` (^1.30.0) | Kafka admin operations (topic management) |
13
- | **KafkaSchemaRegistryHelper** | `BaseHelper` | `@platformatic/kafka` (^1.30.0) | Confluent Schema Registry integration |
14
- | **MQTTClientHelper** | `BaseHelper` | `mqtt` (^5.15.0) | MQTT broker messaging -- real-time events, IoT |
15
- | **QueueHelper** | `BaseHelper` | None | In-memory generator queue -- sequential tasks, single process |
7
+ # Queue
16
8
 
17
- #### Common Operations
9
+ The Queue helpers move work between processes. Pick a backend: BullMQ for durable jobs, an in-memory queue for single-process sequencing, or MQTT for lightweight pub/sub.
18
10
 
19
- | Helper | Subscribe / Consume | Publish / Produce |
20
- |--------|---------------------|-------------------|
21
- | **BullMQ** | Create with `role: 'worker'` | `queue.add(name, data)` via the exposed BullMQ `Queue` instance |
22
- | **Kafka** | `consumer.start({ topics })` | `producer.getProducer().send({ messages })` |
23
- | **MQTT** | `subscribe({ topics })` | `publish({ topic, message })` |
24
- | **In-Memory** | `new QueueHelper({ onMessage })` | `enqueue(payload)` |
11
+ ## In one example
25
12
 
26
- #### Import Paths
13
+ Create a Redis-backed producer and worker with `BullMQHelper`.
27
14
 
28
15
  ```typescript
29
- // In-memory queue (from base package)
30
- import { QueueHelper, QueueStatuses } from '@venizia/ignis-helpers';
31
- import type { TQueueStatus, TQueueElement } from '@venizia/ignis-helpers';
32
-
33
- // BullMQ (separate export path)
16
+ import { RedisSingleHelper } from '@venizia/ignis-helpers';
34
17
  import { BullMQHelper } from '@venizia/ignis-helpers/bullmq';
35
- import type { TBullQueueRole } from '@venizia/ignis-helpers/bullmq';
36
-
37
- // Kafka (separate export path)
38
- import {
39
- KafkaProducerHelper,
40
- KafkaConsumerHelper,
41
- KafkaAdminHelper,
42
- KafkaSchemaRegistryHelper,
43
- BaseKafkaHelper,
44
- } from '@venizia/ignis-helpers/kafka';
45
- import type {
46
- IKafkaProducerOptions,
47
- IKafkaConsumerOptions,
48
- IKafkaAdminOptions,
49
- IKafkaSchemaRegistryOptions,
50
- IKafkaConsumeStartOptions,
51
- IKafkaTransactionContext,
52
- TKafkaBrokerEventCallback,
53
- TKafkaMessageCallback,
54
- TKafkaMessageDoneCallback,
55
- TKafkaMessageErrorCallback,
56
- TKafkaGroupJoinCallback,
57
- TKafkaGroupLeaveCallback,
58
- TKafkaGroupRebalanceCallback,
59
- TKafkaHeartbeatErrorCallback,
60
- TKafkaLagCallback,
61
- TKafkaLagErrorCallback,
62
- } from '@venizia/ignis-helpers/kafka';
63
-
64
- // MQTT (separate export path)
65
- import { MQTTClientHelper } from '@venizia/ignis-helpers/mqtt';
66
- import type { IMQTTClientOptions } from '@venizia/ignis-helpers/mqtt';
67
- ```
68
-
69
- ## Creating an Instance
70
18
 
71
- All queue helpers extend `BaseHelper` (Kafka helpers via `BaseKafkaHelper`), providing scoped logging via `this.logger`.
19
+ const redis = new RedisSingleHelper({ name: 'queue-redis', host: 'localhost', port: 6379, password: 'secret' });
72
20
 
73
- ### BullMQHelper
74
-
75
- The `BullMQHelper` wraps the BullMQ library for Redis-backed job queuing. It operates in one of two roles: `'queue'` (producer) or `'worker'` (consumer). The role is set at construction time and determines which BullMQ primitives are initialized.
21
+ const producer = BullMQHelper.newInstance({
22
+ queueName: 'email-queue',
23
+ identifier: 'email-producer',
24
+ role: 'queue',
25
+ redisConnection: redis,
26
+ });
76
27
 
77
- ```typescript
78
- import { RedisSingleHelper } from '@venizia/ignis-helpers';
79
- import { BullMQHelper } from '@venizia/ignis-helpers/bullmq';
28
+ await producer.queue.add('send-welcome', { email: 'user@example.com', template: 'welcome' });
80
29
 
81
- const worker = new BullMQHelper({
30
+ const worker = BullMQHelper.newInstance({
82
31
  queueName: 'email-queue',
83
32
  identifier: 'email-worker',
84
33
  role: 'worker',
85
- redisConnection: redisHelper,
86
- numberOfWorker: 3,
87
- lockDuration: 90 * 60 * 1000,
88
- onWorkerData: async (job) => {
89
- console.log(`Processing job ${job.id}:`, job.data);
34
+ redisConnection: redis,
35
+ onWorkerData: async job => {
36
+ console.log(`Processing ${job.id}:`, job.data);
90
37
  return { status: 'sent' };
91
38
  },
92
- onWorkerDataCompleted: async (job, result) => {
93
- console.log(`Job ${job.id} completed:`, result);
94
- },
95
- onWorkerDataFail: async (job, error) => {
96
- console.error(`Job ${job?.id} failed:`, error.message);
97
- },
98
- });
99
- ```
100
-
101
- #### IBullMQOptions
102
-
103
- `IBullMQOptions<TQueueElement = any, TQueueResult = any>`
104
-
105
- | Option | Type | Default | Description |
106
- |--------|------|---------|-------------|
107
- | `queueName` | `string` | -- | Name of the BullMQ queue. Must be non-empty. |
108
- | `identifier` | `string` | -- | Unique identifier used for scoped logging. |
109
- | `role` | `TBullQueueRole` | -- | `'queue'` (producer) or `'worker'` (consumer). |
110
- | `redisConnection` | `IRedisHelper` | -- | Redis helper instance. The helper calls `duplicateClient()` internally. |
111
- | `numberOfWorker` | `number` | `1` | Worker concurrency (number of jobs processed in parallel). |
112
- | `lockDuration` | `number` | `5400000` | Job lock duration in milliseconds (default: 90 minutes). |
113
- | `onWorkerData` | `(job: Job<TQueueElement, TQueueResult>) => Promise<any>` | `undefined` | Job processing callback. If omitted, the worker logs job details. |
114
- | `onWorkerDataCompleted` | `(job: Job<TQueueElement, TQueueResult>, result: any) => Promise<void>` | `undefined` | Callback fired when a job completes successfully. |
115
- | `onWorkerDataFail` | `(job: Job<TQueueElement, TQueueResult> \| undefined, error: Error) => Promise<void>` | `undefined` | Callback fired when a job fails. |
116
-
117
- > [!IMPORTANT]
118
- > Pass an `IRedisHelper` instance to `redisConnection`, **not** the raw ioredis client. The helper internally calls `redisConnection.duplicateClient()` to create dedicated connections for the queue and worker.
119
-
120
- ### MQTTClientHelper
121
-
122
- The `MQTTClientHelper` provides a pub/sub interface to an MQTT broker. The client connects automatically during construction.
123
-
124
- ```typescript
125
- import { MQTTClientHelper } from '@venizia/ignis-helpers/mqtt';
126
-
127
- const mqttClient = new MQTTClientHelper({
128
- identifier: 'sensor-client',
129
- url: 'mqtt://localhost:1883',
130
- options: {
131
- username: 'user',
132
- password: 'password',
133
- },
134
- onMessage: ({ topic, message }) => {
135
- console.log(`Received on ${topic}:`, message.toString());
136
- },
137
- onConnect: () => {
138
- console.log('Connected to MQTT broker');
139
- },
140
- onDisconnect: () => {
141
- console.log('Disconnected from MQTT broker');
142
- },
143
- onError: (error) => {
144
- console.error('MQTT error:', error);
145
- },
146
- onClose: (error) => {
147
- if (error) console.error('Connection closed with error:', error);
148
- },
149
- });
150
- ```
151
-
152
- #### IMQTTClientOptions
153
-
154
- | Option | Type | Default | Description |
155
- |--------|------|---------|-------------|
156
- | `identifier` | `string` | -- | Unique identifier for scoped logging. |
157
- | `url` | `string` | -- | MQTT broker URL (e.g., `mqtt://localhost:1883`). Must be non-empty. |
158
- | `options` | `mqtt.IClientOptions` | -- | MQTT.js client options (username, password, keepalive, etc.). |
159
- | `onMessage` | `(opts: { topic: string; message: Buffer }) => void` | -- | Message handler. Required. |
160
- | `onConnect` | `() => void` | `undefined` | Callback fired when the client connects to the broker. |
161
- | `onDisconnect` | `() => void` | `undefined` | Callback fired on disconnection. |
162
- | `onError` | `(error: Error) => void` | `undefined` | Callback fired on client errors. |
163
- | `onClose` | `(error?: Error) => void` | `undefined` | Callback fired when the connection is closed. |
164
-
165
- > [!NOTE]
166
- > At connect time, `MQTTClientHelper` logs the broker `url` through `redactUrlCredentials()` and the `options` object through `redactSecrets()`. If `url` embeds a password (e.g. `mqtts://user:hunter2@broker:8883`), the password never reaches the log -- only `mqtts://user:[REDACTED]@broker:8883` does.
167
-
168
- ### QueueHelper
169
-
170
- The `QueueHelper` is a generator-based, in-memory queue with a built-in state machine. It processes enqueued items one at a time, making it suitable for sequential task processing within a single process.
171
-
172
- ```typescript
173
- import { QueueHelper } from '@venizia/ignis-helpers';
174
-
175
- const queue = new QueueHelper<string>({
176
- identifier: 'task-queue',
177
- autoDispatch: true,
178
- onMessage: async ({ identifier, queueElement }) => {
179
- console.log(`[${identifier}] Processing:`, queueElement.payload);
180
- },
181
- onDataEnqueue: async ({ identifier, queueElement }) => {
182
- console.log(`[${identifier}] Enqueued:`, queueElement.payload);
183
- },
184
- onDataDequeue: async ({ identifier, queueElement }) => {
185
- console.log(`[${identifier}] Dequeued:`, queueElement.payload);
186
- },
187
- onStateChange: async ({ identifier, from, to }) => {
188
- console.log(`[${identifier}] State: ${from} -> ${to}`);
189
- },
190
- });
191
- ```
192
-
193
- #### IQueueCallback
194
-
195
- `IQueueCallback<TElementPayload>`
196
-
197
- | Option | Type | Default | Description |
198
- |--------|------|---------|-------------|
199
- | `identifier` | `string` | -- | Unique identifier for scoped logging. |
200
- | `autoDispatch` | `boolean` | `true` | If `true`, automatically triggers processing when an element is enqueued. |
201
- | `onMessage` | `(opts: { identifier: string; queueElement: TQueueElement<T> }) => ValueOrPromise<void>` | `undefined` | Message processing callback. If omitted, the generator exits immediately. |
202
- | `onDataEnqueue` | `(opts: { identifier: string; queueElement: TQueueElement<T> }) => ValueOrPromise<void>` | `undefined` | Callback fired after an element is added to the queue. |
203
- | `onDataDequeue` | `(opts: { identifier: string; queueElement: TQueueElement<T> }) => ValueOrPromise<void>` | `undefined` | Callback fired after an element is removed from the queue. |
204
- | `onStateChange` | `(opts: { identifier: string; from: TQueueStatus; to: TQueueStatus }) => ValueOrPromise<void>` | `undefined` | Callback fired on every state transition. |
205
-
206
- #### TQueueElement
207
-
208
- Each element in the queue is wrapped in a `TQueueElement`:
209
-
210
- ```typescript
211
- type TQueueElement<T> = { isLocked: boolean; payload: T };
212
- ```
213
-
214
- ### Kafka Producer
215
-
216
- The `KafkaProducerHelper` wraps `@platformatic/kafka` Producer with lifecycle management, health tracking, and transaction support.
217
-
218
- ```typescript
219
- import { KafkaProducerHelper } from '@venizia/ignis-helpers/kafka';
220
-
221
- const producer = KafkaProducerHelper.newInstance({
222
- bootstrapBrokers: ['127.0.0.1:29092'],
223
- clientId: 'my-producer',
224
- acks: -1,
225
- idempotent: true,
226
- onBrokerConnect: ({ broker }) => {
227
- console.log(`Connected to ${broker.host}:${broker.port}`);
228
- },
229
- onBrokerDisconnect: ({ broker }) => {
230
- console.log(`Disconnected from ${broker.host}:${broker.port}`);
231
- },
232
- });
233
- ```
234
-
235
- #### IKafkaProducerOptions
236
-
237
- `IKafkaProducerOptions<KeyType, ValueType, HeaderKeyType, HeaderValueType>` extends `IKafkaConnectionOptions`.
238
-
239
- | Option | Type | Default | Description |
240
- |--------|------|---------|-------------|
241
- | `bootstrapBrokers` | `string[]` | -- | Kafka broker addresses. |
242
- | `clientId` | `string` | -- | Client identifier. |
243
- | `identifier` | `string` | `'kafka-producer'` | Scoped logging identifier. |
244
- | `acks` | `0 \| 1 \| -1` | -- | Acknowledgment mode. `0` = none, `1` = leader, `-1` = all ISR. |
245
- | `idempotent` | `boolean` | -- | Enable idempotent producer. |
246
- | `transactionalId` | `string` | -- | Transactional ID (required for transactions with `idempotent: true`). |
247
- | `compression` | `CompressionAlgorithmValue` | -- | Message compression algorithm. |
248
- | `strict` | `boolean` | `true` | Strict mode for topic validation. |
249
- | `autocreateTopics` | `boolean` | `false` | Auto-create topics on send. |
250
- | `retries` | `number` | `3` | Number of retries on failure. |
251
- | `retryDelay` | `number` | `1000` | Delay between retries in milliseconds. |
252
- | `shutdownTimeout` | `number` | `30000` | Graceful shutdown timeout in milliseconds. |
253
- | `serializers` | `Partial<Serializers<...>>` | -- | Custom key/value/header serializers. |
254
- | `registry` | `SchemaRegistry<...>` | -- | Schema registry for serialization. |
255
- | `sasl` | `SASLOptions` | -- | SASL authentication options. |
256
- | `tls` | `TLSOptions` | -- | TLS connection options. |
257
- | `ssl` | `SSLOptions` | -- | SSL connection options. |
258
- | `connectTimeout` | `number` | -- | Connection timeout in milliseconds. |
259
- | `requestTimeout` | `number` | -- | Request timeout in milliseconds. |
260
- | `onBrokerConnect` | `TKafkaBrokerEventCallback` | -- | Callback when a broker connects. |
261
- | `onBrokerDisconnect` | `TKafkaBrokerEventCallback` | -- | Callback when a broker disconnects. |
262
-
263
- ### Kafka Consumer
264
-
265
- The `KafkaConsumerHelper` wraps `@platformatic/kafka` Consumer with message processing callbacks, consumer group lifecycle events, and lag monitoring.
266
-
267
- ```typescript
268
- import { KafkaConsumerHelper } from '@venizia/ignis-helpers/kafka';
269
-
270
- const consumer = KafkaConsumerHelper.newInstance({
271
- bootstrapBrokers: ['127.0.0.1:29092'],
272
- clientId: 'my-consumer',
273
- groupId: 'my-consumer-group',
274
- onMessage: async ({ message }) => {
275
- console.log('Received:', message.value);
276
- await message.commit();
277
- },
278
- onMessageError: ({ error }) => {
279
- console.error('Error:', error);
280
- },
281
- onGroupJoin: ({ groupId, memberId }) => {
282
- console.log(`Joined ${groupId} as ${memberId}`);
283
- },
284
- });
285
- ```
286
-
287
- #### IKafkaConsumerOptions
288
-
289
- `IKafkaConsumerOptions<KeyType, ValueType, HeaderKeyType, HeaderValueType>` extends `IKafkaConnectionOptions`.
290
-
291
- | Option | Type | Default | Description |
292
- |--------|------|---------|-------------|
293
- | `bootstrapBrokers` | `string[]` | -- | Kafka broker addresses. |
294
- | `clientId` | `string` | -- | Client identifier. |
295
- | `groupId` | `string` | -- | Consumer group ID. Required. |
296
- | `identifier` | `string` | `'kafka-consumer'` | Scoped logging identifier. |
297
- | `groupProtocol` | `'classic' \| 'consumer'` | `'classic'` | Consumer group protocol. |
298
- | `groupInstanceId` | `string` | -- | Static group membership instance ID. |
299
- | `autocommit` | `boolean \| number` | `false` | Auto-commit offsets. `false` = manual, `true` or number = interval. |
300
- | `sessionTimeout` | `number` | `30000` | Session timeout in milliseconds. |
301
- | `heartbeatInterval` | `number` | `3000` | Heartbeat interval in milliseconds. |
302
- | `rebalanceTimeout` | `number` | `sessionTimeout` | Rebalance timeout in milliseconds. |
303
- | `highWaterMark` | `number` | `1024` | Stream high water mark. |
304
- | `minBytes` | `number` | `1` | Minimum bytes to fetch per request. |
305
- | `maxBytes` | `number` | -- | Maximum bytes to fetch per request. |
306
- | `maxWaitTime` | `number` | -- | Maximum wait time for fetch in milliseconds. |
307
- | `metadataMaxAge` | `number` | `300000` | Metadata cache max age in milliseconds. |
308
- | `retries` | `number` | `3` | Number of retries on failure. |
309
- | `retryDelay` | `number` | `1000` | Delay between retries in milliseconds. |
310
- | `shutdownTimeout` | `number` | `30000` | Graceful shutdown timeout in milliseconds. |
311
- | `deserializers` | `Partial<Deserializers<...>>` | -- | Custom key/value/header deserializers. |
312
- | `registry` | `SchemaRegistry<...>` | -- | Schema registry for deserialization. |
313
- | `onBrokerConnect` | `TKafkaBrokerEventCallback` | -- | Callback when a broker connects. |
314
- | `onBrokerDisconnect` | `TKafkaBrokerEventCallback` | -- | Callback when a broker disconnects. |
315
- | `onMessage` | `TKafkaMessageCallback` | -- | Message processing callback. |
316
- | `onMessageDone` | `TKafkaMessageDoneCallback` | -- | Callback after message processing completes. |
317
- | `onMessageError` | `TKafkaMessageErrorCallback` | -- | Callback on message processing error. |
318
- | `onGroupJoin` | `TKafkaGroupJoinCallback` | -- | Callback when consumer joins the group. |
319
- | `onGroupLeave` | `TKafkaGroupLeaveCallback` | -- | Callback when consumer leaves the group. |
320
- | `onGroupRebalance` | `TKafkaGroupRebalanceCallback` | -- | Callback on group rebalance. |
321
- | `onHeartbeatError` | `TKafkaHeartbeatErrorCallback` | -- | Callback on heartbeat error. |
322
- | `onLag` | `TKafkaLagCallback` | -- | Callback with lag offset data. |
323
- | `onLagError` | `TKafkaLagErrorCallback` | -- | Callback on lag monitoring error. |
324
-
325
- ### Kafka Admin
326
-
327
- The `KafkaAdminHelper` wraps `@platformatic/kafka` Admin for topic and cluster management.
328
-
329
- ```typescript
330
- import { KafkaAdminHelper } from '@venizia/ignis-helpers/kafka';
331
-
332
- const admin = KafkaAdminHelper.newInstance({
333
- bootstrapBrokers: ['127.0.0.1:29092'],
334
- clientId: 'my-admin',
335
- onBrokerConnect: ({ broker }) => {
336
- console.log(`Connected to ${broker.host}:${broker.port}`);
337
- },
338
39
  });
339
-
340
- // Access the full Admin API directly
341
- const adminClient = admin.getAdmin();
342
- await adminClient.createTopics({ topics: ['my-topic'], partitions: 3, replicas: 1 });
343
40
  ```
344
41
 
345
- #### IKafkaAdminOptions
42
+ `RedisSingleHelper` sets `maxRetriesPerRequest: null` automatically, so it works with BullMQ out of the box - no extra Redis configuration needed for this example.
346
43
 
347
- | Option | Type | Default | Description |
348
- |--------|------|---------|-------------|
349
- | `bootstrapBrokers` | `string[]` | -- | Kafka broker addresses. |
350
- | `clientId` | `string` | -- | Client identifier. |
351
- | `identifier` | `string` | `'kafka-admin'` | Scoped logging identifier. |
352
- | `retries` | `number` | `3` | Number of retries on failure. |
353
- | `retryDelay` | `number` | `1000` | Delay between retries in milliseconds. |
354
- | `shutdownTimeout` | `number` | `30000` | Graceful shutdown timeout in milliseconds. |
355
- | `onBrokerConnect` | `TKafkaBrokerEventCallback` | -- | Callback when a broker connects. |
356
- | `onBrokerDisconnect` | `TKafkaBrokerEventCallback` | -- | Callback when a broker disconnects. |
44
+ ## How it works
357
45
 
358
- ### Kafka Schema Registry
46
+ - **Three backends, one family.** `BullMQHelper`, `SequentialQueueHelper`, and `MQTTClientHelper` all live under `@venizia/ignis-helpers`. A fourth backend, Kafka, is documented separately - see [Kafka Helpers](/extensions/helpers/kafka/).
359
47
 
360
- The `KafkaSchemaRegistryHelper` wraps `@platformatic/kafka` ConfluentSchemaRegistry for Avro/Protobuf/JSON schema integration with producer and consumer helpers.
48
+ | Backend | Class | Peer dependency | Reach for it when |
49
+ |---------|-------|------------------|--------------------|
50
+ | BullMQ | `BullMQHelper` | `bullmq` | Jobs must survive a process restart or run across multiple workers |
51
+ | In-memory | `SequentialQueueHelper` (alias `QueueHelper`) | none | Sequential, single-process work that does not need persistence |
52
+ | MQTT | `MQTTClientHelper` | `mqtt` | Pub/sub for IoT and lightweight real-time events, not job processing |
361
53
 
362
- ```typescript
363
- import { KafkaSchemaRegistryHelper, KafkaProducerHelper } from '@venizia/ignis-helpers/kafka';
54
+ - **`BullMQHelper` takes one `role` per instance, fixed at construction.**
364
55
 
365
- const schemaRegistry = KafkaSchemaRegistryHelper.newInstance({
366
- url: 'http://localhost:8081',
367
- });
56
+ | `role` | Property | Use |
57
+ |---|---|---|
58
+ | `'queue'` | `.queue` (BullMQ `Queue`) | Producers call `.add()` |
59
+ | `'worker'` | `.worker` (BullMQ `Worker`) | Driven by your `onWorkerData` callback |
368
60
 
369
- const producer = KafkaProducerHelper.newInstance({
370
- bootstrapBrokers: ['127.0.0.1:29092'],
371
- clientId: 'my-producer',
372
- registry: schemaRegistry.getRegistry(),
373
- });
374
- ```
375
-
376
- #### IKafkaSchemaRegistryOptions
61
+ - **One Redis helper backs any number of queues and workers.** The helper always calls `redisConnection.duplicateClient()` to open a dedicated connection for whichever role it owns. It never reuses your client directly.
62
+ - **`SequentialQueueHelper` runs one element at a time**, in a `WAITING -> PROCESSING -> WAITING` loop driven by `onMessage`. Two calls change that loop:
377
63
 
378
- | Option | Type | Default | Description |
379
- |--------|------|---------|-------------|
380
- | `url` | `string` | -- | Schema Registry URL. |
381
- | `identifier` | `string` | `'kafka-schema-registry'` | Scoped logging identifier. |
382
- | `auth` | `object` | -- | Authentication credentials. |
383
- | `protobufTypeMapper` | `function` | -- | Protobuf type mapping function. |
384
- | `jsonValidateSend` | `boolean` | -- | Validate JSON schemas on send. |
64
+ | Call | Effect |
65
+ |---|---|
66
+ | `lock()` | Pauses processing at `LOCKED`. Elements still enqueue; nothing processes until `unlock()`. |
67
+ | `settle()` / `close()` | Drains the queue, then moves to the terminal `SETTLED` state. |
385
68
 
386
- ## Usage
69
+ Full option tables, the complete state machine, and `HfQueueHelper` (the low-level FIFO primitive underneath) are in the [Full reference](/extensions/helpers/queue/reference).
387
70
 
388
- ### BullMQ -- Adding Jobs
71
+ ## Common tasks
389
72
 
390
- When created with `role: 'queue'`, the helper exposes a `queue` property (a BullMQ `Queue` instance) for adding jobs.
73
+ ### Enqueue a job from a producer
391
74
 
392
75
  ```typescript
393
- const producer = new BullMQHelper({
394
- queueName: 'email-queue',
395
- identifier: 'email-producer',
396
- role: 'queue',
397
- redisConnection: redisHelper,
398
- });
399
-
400
- // Add a job via the BullMQ Queue API
401
- await producer.queue.add('send-welcome', { email: 'user@example.com', template: 'welcome' });
402
76
  await producer.queue.add('send-reset', { email: 'user@example.com', token: 'abc123' });
403
77
  ```
404
78
 
405
- > [!TIP]
406
- > You can also use the static factory method: `BullMQHelper.newInstance({ ... })` which is equivalent to `new BullMQHelper({ ... })`.
79
+ Jobs default to `removeOnComplete: true, removeOnFail: true` - BullMQ does not retain job records after they finish.
407
80
 
408
- #### Default Job Options
81
+ ### Process jobs with a worker
409
82
 
410
- Jobs are created with these defaults:
83
+ `numberOfWorker` sets concurrency. `onWorkerDataFail` receives the job (possibly `undefined`) and the error.
411
84
 
412
85
  ```typescript
413
- defaultJobOptions: {
414
- removeOnComplete: true,
415
- removeOnFail: true,
416
- }
417
- ```
418
-
419
- ### BullMQ -- Processing Jobs
420
-
421
- When created with `role: 'worker'`, the helper initializes a BullMQ `Worker` that listens for jobs on the specified queue.
422
-
423
- ```typescript
424
- const consumer = new BullMQHelper<{ email: string }, { status: string }>({
86
+ const worker = BullMQHelper.newInstance({
425
87
  queueName: 'email-queue',
426
- identifier: 'email-consumer',
88
+ identifier: 'email-worker',
427
89
  role: 'worker',
428
- redisConnection: redisHelper,
90
+ redisConnection: redis,
429
91
  numberOfWorker: 3,
430
- lockDuration: 10 * 60 * 1000, // 10 minutes
431
- onWorkerData: async (job) => {
92
+ onWorkerData: async job => {
432
93
  await sendEmail(job.data.email);
433
94
  return { status: 'sent' };
434
95
  },
435
- onWorkerDataCompleted: async (job, result) => {
436
- console.log(`Job ${job.id} done:`, result);
437
- },
438
96
  onWorkerDataFail: async (job, error) => {
439
97
  console.error(`Job ${job?.id} failed:`, error.message);
440
98
  },
441
99
  });
442
100
  ```
443
101
 
444
- If `onWorkerData` is not provided, the worker logs the job's `id`, `name`, and `data` at the info level.
102
+ ### The Redis connection requirement
445
103
 
446
- ### BullMQ -- Redis Cluster
104
+ Pass an `IRedisHelper` instance, not a raw ioredis client. `BullMQHelper` calls `redisConnection.duplicateClient()` internally.
447
105
 
448
- When using Redis Cluster with BullMQ, use `RedisClusterHelper`. Set `maxRetriesPerRequest: null` inside `clusterOptions.redisOptions` -- this is **required** by BullMQ.
106
+ | Redis helper | Sets `maxRetriesPerRequest: null`? |
107
+ |--------------|-------------------------------------|
108
+ | `RedisSingleHelper` | Automatically |
109
+ | `RedisSentinelHelper` | Automatically |
110
+ | `RedisClusterHelper` | No - set it yourself, BullMQ requires it |
449
111
 
450
112
  ```typescript
451
113
  import { RedisClusterHelper } from '@venizia/ignis-helpers';
452
- import { BullMQHelper } from '@venizia/ignis-helpers/bullmq';
453
114
 
454
- const redisHelper = new RedisClusterHelper({
115
+ const clusterRedis = new RedisClusterHelper({
455
116
  name: 'cluster-redis',
456
- nodes: [
457
- { host: 'node1.redis.example.com', port: 6379 },
458
- { host: 'node2.redis.example.com', port: 6379 },
459
- { host: 'node3.redis.example.com', port: 6379 },
460
- ],
117
+ nodes: [{ host: 'node1.redis.example.com', port: 6379 }],
461
118
  clusterOptions: {
462
- enableReadyCheck: true,
463
- scaleReads: 'slave',
464
- redisOptions: {
465
- password: 'your-password',
466
- tls: {},
467
- maxRetriesPerRequest: null, // Required by BullMQ
468
- },
469
- },
470
- });
471
-
472
- const worker = BullMQHelper.newInstance({
473
- queueName: 'my-queue',
474
- identifier: 'cluster-worker',
475
- role: 'worker',
476
- redisConnection: redisHelper,
477
- onWorkerData: async (job) => {
478
- // process job
479
- },
480
- });
481
- ```
482
-
483
- ### BullMQ -- Graceful Shutdown
484
-
485
- Call `close()` to gracefully shut down both the worker and queue connections.
486
-
487
- ```typescript
488
- await producer.close();
489
- await consumer.close();
490
- ```
491
-
492
- `close()` calls `worker.close()` and `queue.close()` in sequence. If closing fails, it logs the error and re-throws.
493
-
494
- ### MQTT -- Subscribe and Publish
495
-
496
- After the client connects to the broker, use `subscribe()` and `publish()` for topic-based messaging.
497
-
498
- ```typescript
499
- // Subscribe to multiple topics
500
- await mqttClient.subscribe({ topics: ['sensors/temperature', 'sensors/humidity'] });
501
-
502
- // Publish a string message
503
- await mqttClient.publish({ topic: 'sensors/temperature', message: '23.5' });
504
-
505
- // Publish a Buffer message
506
- await mqttClient.publish({ topic: 'sensors/raw', message: Buffer.from([0x01, 0x02]) });
507
- ```
508
-
509
- > [!NOTE]
510
- > Both `subscribe()` and `publish()` reject with an `ApplicationError` (status 400) if the MQTT client is not connected. Ensure the connection is established before calling these methods.
511
-
512
- ### MQTT -- Event Handling
513
-
514
- The `MQTTClientHelper` calls `configure()` automatically during construction. Once connected, the `onMessage` callback receives messages for all subscribed topics.
515
-
516
- ```typescript
517
- const client = new MQTTClientHelper({
518
- identifier: 'iot-gateway',
519
- url: 'mqtt://broker.example.com:1883',
520
- options: { keepalive: 60 },
521
- onConnect: () => {
522
- // Subscribe once connected
523
- client.subscribe({ topics: ['devices/+/status'] });
524
- },
525
- onMessage: ({ topic, message }) => {
526
- const deviceId = topic.split('/')[1];
527
- console.log(`Device ${deviceId}:`, message.toString());
528
- },
529
- onError: (error) => {
530
- console.error('Connection error:', error.message);
531
- },
532
- onClose: () => {
533
- console.log('Connection closed');
534
- },
535
- });
536
- ```
537
-
538
- ### Kafka -- Producing Messages
539
-
540
- Use `getProducer()` to access the underlying `@platformatic/kafka` Producer and send messages.
541
-
542
- ```typescript
543
- const producer = KafkaProducerHelper.newInstance({
544
- bootstrapBrokers: ['127.0.0.1:29092'],
545
- clientId: 'my-producer',
546
- acks: -1,
547
- });
548
-
549
- // Send messages via the underlying producer
550
- await producer.getProducer().send({
551
- messages: [
552
- { topic: 'orders', key: 'order-1', value: JSON.stringify({ item: 'widget' }) },
553
- ],
554
- });
555
-
556
- // Health check
557
- producer.isHealthy(); // true when connected to a broker
558
- ```
559
-
560
- ### Kafka -- Consuming Messages
561
-
562
- Call `start()` to begin consuming from topics. Messages are delivered via the `onMessage` callback.
563
-
564
- ```typescript
565
- const consumer = KafkaConsumerHelper.newInstance({
566
- bootstrapBrokers: ['127.0.0.1:29092'],
567
- clientId: 'my-consumer',
568
- groupId: 'my-group',
569
- onMessage: async ({ message }) => {
570
- console.log('Key:', message.key, 'Value:', message.value);
571
- await message.commit();
119
+ redisOptions: { maxRetriesPerRequest: null }, // required by BullMQ
572
120
  },
573
- onMessageDone: async ({ message }) => {
574
- console.log('Processing complete for offset:', message.offset);
575
- },
576
- onMessageError: ({ error, message }) => {
577
- console.error('Processing failed:', error.message);
578
- },
579
- });
580
-
581
- await consumer.start({
582
- topics: ['orders'],
583
- mode: 'committed', // Default: 'committed'
584
- fallbackMode: 'latest', // Default: 'latest'
585
121
  });
586
122
  ```
587
123
 
588
- #### IKafkaConsumeStartOptions
589
-
590
- | Option | Type | Default | Description |
591
- |--------|------|---------|-------------|
592
- | `topics` | `string[]` | -- | Topics to consume from. |
593
- | `mode` | `MessagesStreamModeValue` | `'committed'` | Consume mode. |
594
- | `fallbackMode` | `MessagesStreamFallbackModeValue` | `'latest'` | Fallback mode when no committed offset exists. |
595
-
596
- ### Kafka -- Lag Monitoring
597
-
598
- Monitor consumer lag to detect processing delays.
124
+ ### In-memory queue for single-process sequencing
599
125
 
600
126
  ```typescript
601
- consumer.startLagMonitoring({
602
- topics: ['orders'],
603
- interval: 30_000, // Default: 30 seconds
604
- });
127
+ import { SequentialQueueHelper } from '@venizia/ignis-helpers';
605
128
 
606
- // Stop monitoring
607
- consumer.stopLagMonitoring();
608
- ```
609
-
610
- Use the `onLag` and `onLagError` callbacks to react to lag data:
611
-
612
- ```typescript
613
- const consumer = KafkaConsumerHelper.newInstance({
614
- // ...
615
- onLag: ({ lag }) => {
616
- console.log('Current lag offsets:', lag);
617
- },
618
- onLagError: ({ error }) => {
619
- console.error('Lag monitoring error:', error);
620
- },
621
- });
622
- ```
623
-
624
- ### Kafka -- Transactions
625
-
626
- The `KafkaProducerHelper` supports exactly-once semantics via transactions. Requires `transactionalId` and `idempotent: true`.
627
-
628
- ```typescript
629
- const producer = KafkaProducerHelper.newInstance({
630
- bootstrapBrokers: ['127.0.0.1:29092'],
631
- clientId: 'transactional-producer',
632
- transactionalId: 'my-tx-id',
633
- idempotent: true,
634
- acks: -1,
635
- });
636
-
637
- const result = await producer.runInTransaction(async ({ send, addConsumer, addOffset }) => {
638
- return send({
639
- messages: [
640
- { topic: 'orders', key: 'o1', value: JSON.stringify({ status: 'created' }) },
641
- ],
642
- });
643
- });
644
- ```
645
-
646
- The transaction context provides:
647
-
648
- | Method | Description |
649
- |--------|-------------|
650
- | `send(opts)` | Send messages within the transaction. Returns `ProduceResult`. |
651
- | `addConsumer(consumer)` | Add a consumer to the transaction for read-process-write patterns. |
652
- | `addOffset(message)` | Commit consumer offsets as part of the transaction. |
653
- | `transaction` | The underlying transaction object for advanced operations. |
654
-
655
- If the callback throws, the transaction is automatically aborted.
656
-
657
- ### Kafka -- Health Checks
658
-
659
- All Kafka helpers provide health checking via `BaseKafkaHelper`:
660
-
661
- ```typescript
662
- producer.isHealthy(); // true when connected
663
- consumer.isReady(); // true when connected AND active (consuming)
664
- admin.getHealthStatus(); // 'connected' | 'disconnected' | 'unknown'
665
- ```
666
-
667
- ### Kafka -- Graceful Shutdown
668
-
669
- All Kafka helpers support graceful shutdown with an optional force flag and configurable timeout (default: 30 seconds).
670
-
671
- ```typescript
672
- // Graceful shutdown (waits up to shutdownTimeout, then forces)
673
- await producer.close();
674
- await consumer.close();
675
- await admin.close();
676
-
677
- // Force immediate shutdown
678
- await producer.close({ isForce: true });
679
- await consumer.close({ isForce: true });
680
- ```
681
-
682
- For consumers, `close()` also stops lag monitoring and closes the message stream before closing the client.
683
-
684
- ### In-Memory Queue -- Enqueueing and Processing
685
-
686
- With `autoDispatch: true` (default), elements are processed automatically as they are enqueued.
687
-
688
- ```typescript
689
- import { QueueHelper } from '@venizia/ignis-helpers';
690
-
691
- const queue = new QueueHelper<{ task: string; priority: number }>({
129
+ const queue = new SequentialQueueHelper<{ task: string }>({
692
130
  identifier: 'task-processor',
693
131
  onMessage: async ({ queueElement }) => {
694
- console.log('Processing:', queueElement.payload.task);
695
132
  await performTask(queueElement.payload);
696
133
  },
697
134
  });
698
135
 
699
- // Elements are processed one at a time, in order
700
- await queue.enqueue({ task: 'resize-image', priority: 1 });
701
- await queue.enqueue({ task: 'send-notification', priority: 2 });
702
- ```
703
-
704
- #### Manual Dispatch
705
-
706
- Set `autoDispatch: false` to control when processing begins. Call `nextMessage()` to trigger processing of the next element.
707
-
708
- ```typescript
709
- const queue = new QueueHelper<string>({
710
- identifier: 'manual-queue',
711
- autoDispatch: false,
712
- onMessage: async ({ queueElement }) => {
713
- console.log('Processing:', queueElement.payload);
714
- },
715
- });
716
-
717
- await queue.enqueue('item-1');
718
- await queue.enqueue('item-2');
719
-
720
- // Nothing processed yet -- trigger manually
721
- queue.nextMessage(); // processes 'item-1'
722
- ```
723
-
724
- > [!NOTE]
725
- > `nextMessage()` only triggers processing when the queue state is `WAITING`. It logs a warning and returns if the queue is in any other state.
726
-
727
- ### In-Memory Queue -- State Machine
728
-
729
- The `QueueHelper` uses a state machine to manage its lifecycle:
730
-
731
- ```
732
- WAITING ──enqueue──> PROCESSING ──done──> WAITING
733
- | |
734
- └──lock()──> LOCKED <─┘
735
- |
736
- unlock()──> WAITING
737
- |
738
- settle()──> SETTLED (terminal)
739
- ```
740
-
741
- | State | Value | Description |
742
- |-------|-------|-------------|
743
- | `QueueStatuses.WAITING` | `'000_WAITING'` | Idle, ready to process the next element. |
744
- | `QueueStatuses.PROCESSING` | `'100_PROCESSING'` | Currently handling a message via `onMessage`. |
745
- | `QueueStatuses.LOCKED` | `'200_LOCKED'` | Paused. No new processing until `unlock()` is called. |
746
- | `QueueStatuses.SETTLED` | `'300_SETTLED'` | Terminal state. No more elements accepted. |
747
-
748
- You can validate a state string with `QueueStatuses.isValid(state)`.
749
-
750
- ### In-Memory Queue -- Lock and Unlock
751
-
752
- Use `lock()` / `unlock()` to pause and resume processing without losing queued elements.
753
-
754
- ```typescript
755
- // Pause the queue (e.g., during maintenance)
756
- queue.lock();
757
-
758
- // Elements can still be enqueued while locked,
759
- // but they won't be processed until unlocked
760
- await queue.enqueue('queued-while-locked');
761
-
762
- // Resume processing
763
- queue.unlock({ shouldProcessNextElement: true });
764
-
765
- // Resume without processing the next element
766
- queue.unlock({ shouldProcessNextElement: false });
136
+ await queue.enqueue({ task: 'resize-image' });
767
137
  ```
768
138
 
769
- `lock()` logs an error and returns if the queue is already `LOCKED` or `SETTLED`.
770
-
771
- `unlock()` logs an error and returns if the queue is `SETTLED` (past `LOCKED` state).
772
-
773
- ### In-Memory Queue -- Settling and Closing
774
-
775
- Once settled, the queue rejects new elements and transitions to `SETTLED` after all in-flight work completes.
776
-
777
- ```typescript
778
- // Signal that no more elements will be added
779
- queue.settle();
780
-
781
- // Check if the queue is settled and empty
782
- if (queue.isSettled()) {
783
- console.log('All work done, total events:', queue.getTotalEvent());
784
- }
785
-
786
- // Or close entirely (settle + terminate generator)
787
- queue.close();
788
- ```
789
-
790
- `settle()` sets `isSettleRequested` to `true`. If the queue is not currently processing, it immediately transitions to `SETTLED`. If processing, it transitions to `SETTLED` after the current message completes and the storage is empty.
791
-
792
- `close()` calls `settle()` and then terminates the internal generator via `generator.return()`.
793
-
794
- ## API Summary
795
-
796
- ### BullMQHelper
797
-
798
- | Method | Returns | Description |
799
- |--------|---------|-------------|
800
- | `static newInstance(opts)` | `BullMQHelper` | Factory method, equivalent to `new BullMQHelper(opts)`. |
801
- | `configureQueue()` | `void` | Sets up the BullMQ `Queue` instance. Called automatically for `role: 'queue'`. |
802
- | `configureWorker()` | `void` | Sets up the BullMQ `Worker` instance. Called automatically for `role: 'worker'`. |
803
- | `configure()` | `void` | Delegates to `configureQueue()` or `configureWorker()` based on the `role`. |
804
- | `close()` | `Promise<void>` | Gracefully closes the worker and queue connections. |
805
-
806
- #### Properties
807
-
808
- | Property | Type | Description |
809
- |----------|------|-------------|
810
- | `queue` | `Queue<TQueueElement, TQueueResult>` | BullMQ `Queue` instance (available when `role: 'queue'`). |
811
- | `worker` | `Worker<TQueueElement, TQueueResult>` | BullMQ `Worker` instance (available when `role: 'worker'`). |
812
-
813
- ### KafkaProducerHelper
814
-
815
- | Method | Returns | Description |
816
- |--------|---------|-------------|
817
- | `static newInstance(opts)` | `KafkaProducerHelper` | Factory method. |
818
- | `getProducer()` | `Producer` | Access the underlying `@platformatic/kafka` Producer. |
819
- | `runInTransaction(callback)` | `Promise<ResultType>` | Execute a callback within a Kafka transaction. Auto-commits or aborts. |
820
- | `isHealthy()` | `boolean` | Returns `true` when connected to a broker. |
821
- | `getHealthStatus()` | `TKafkaHealthStatus` | Returns `'connected'`, `'disconnected'`, or `'unknown'`. |
822
- | `close(opts?)` | `Promise<void>` | Graceful shutdown. `opts: { isForce?: boolean }` |
823
-
824
- ### KafkaConsumerHelper
825
-
826
- | Method | Returns | Description |
827
- |--------|---------|-------------|
828
- | `static newInstance(opts)` | `KafkaConsumerHelper` | Factory method. |
829
- | `getConsumer()` | `Consumer` | Access the underlying `@platformatic/kafka` Consumer. |
830
- | `getStream()` | `MessagesStream \| null` | Access the current message stream (null if not started). |
831
- | `start(opts)` | `Promise<void>` | Start consuming. `opts: { topics, mode?, fallbackMode? }` |
832
- | `isReady()` | `boolean` | Returns `true` when connected AND actively consuming. |
833
- | `isHealthy()` | `boolean` | Returns `true` when connected to a broker. |
834
- | `getHealthStatus()` | `TKafkaHealthStatus` | Returns `'connected'`, `'disconnected'`, or `'unknown'`. |
835
- | `startLagMonitoring(opts)` | `void` | Start lag monitoring. `opts: { topics, interval? }` |
836
- | `stopLagMonitoring()` | `void` | Stop lag monitoring. |
837
- | `close(opts?)` | `Promise<void>` | Graceful shutdown. Stops monitoring, closes stream, then client. |
838
-
839
- ### KafkaAdminHelper
840
-
841
- | Method | Returns | Description |
842
- |--------|---------|-------------|
843
- | `static newInstance(opts)` | `KafkaAdminHelper` | Factory method. |
844
- | `getAdmin()` | `Admin` | Access the underlying `@platformatic/kafka` Admin. |
845
- | `isHealthy()` | `boolean` | Returns `true` when connected to a broker. |
846
- | `getHealthStatus()` | `TKafkaHealthStatus` | Returns `'connected'`, `'disconnected'`, or `'unknown'`. |
847
- | `close(opts?)` | `Promise<void>` | Graceful shutdown. `opts: { isForce?: boolean }` |
848
-
849
- ### KafkaSchemaRegistryHelper
850
-
851
- | Method | Returns | Description |
852
- |--------|---------|-------------|
853
- | `static newInstance(opts)` | `KafkaSchemaRegistryHelper` | Factory method. |
854
- | `getRegistry()` | `ConfluentSchemaRegistry` | Access the underlying schema registry. |
855
- | `getSerializers()` | `Serializers` | Get serializers for use with a producer. |
856
- | `getDeserializers()` | `Deserializers` | Get deserializers for use with a consumer. |
857
-
858
- ### MQTTClientHelper
859
-
860
- | Method | Returns | Description |
861
- |--------|---------|-------------|
862
- | `configure()` | `void` | Connects to the MQTT broker. Called automatically by the constructor. |
863
- | `subscribe(opts)` | `Promise<string[]>` | Subscribe to one or more topics. `opts: { topics: string[] }` |
864
- | `publish(opts)` | `Promise<{ topic, message }>` | Publish a message to a topic. `opts: { topic: string; message: string \| Buffer }` |
865
-
866
- ### QueueHelper
867
-
868
- | Method | Returns | Description |
869
- |--------|---------|-------------|
870
- | `enqueue(payload)` | `Promise<void>` | Add an element to the queue. Rejected if settled. |
871
- | `dequeue()` | `TQueueElement<T> \| undefined` | Remove and return the first element. |
872
- | `nextMessage()` | `void` | Manually trigger processing of the next element. Only works in `WAITING` state. |
873
- | `lock()` | `void` | Pause processing. State becomes `LOCKED`. |
874
- | `unlock(opts)` | `void` | Resume processing. `opts: { shouldProcessNextElement?: boolean }` (default: `true`). |
875
- | `settle()` | `void` | Mark queue as settled. No new elements accepted after this. |
876
- | `isSettled()` | `boolean` | Returns `true` if state is `SETTLED` and storage is empty. |
877
- | `close()` | `void` | Settle the queue and terminate the internal generator. |
878
- | `getElementAt(position)` | `TQueueElement<T>` | Peek at an element by index. |
879
- | `getState()` | `TQueueStatus` | Returns the current queue state. |
880
- | `getTotalEvent()` | `number` | Returns the total number of elements ever enqueued. |
881
- | `getProcessingEvents()` | `Set<TQueueElement<T>>` | Returns the set of currently processing elements. |
882
-
883
- ## Troubleshooting
884
-
885
- ### "Invalid queue name"
886
-
887
- **Cause:** The `queueName` option is empty or falsy when creating a BullMQ queue or worker.
888
-
889
- **Fix:** Provide a non-empty `queueName`:
139
+ ### MQTT publish and subscribe
890
140
 
891
141
  ```typescript
892
- // Wrong
893
- new BullMQHelper({ queueName: '', role: 'queue', ... });
894
-
895
- // Correct
896
- new BullMQHelper({ queueName: 'my-email-queue', role: 'queue', ... });
897
- ```
898
-
899
- ### "Invalid client role to configure"
900
-
901
- **Cause:** The `role` option is missing or not one of `'queue'` / `'worker'`.
902
-
903
- **Fix:** Set `role` to either `'queue'` or `'worker'`:
904
-
905
- ```typescript
906
- // Wrong
907
- new BullMQHelper({ role: undefined as any, ... });
908
-
909
- // Correct
910
- new BullMQHelper({ role: 'worker', ... });
911
- ```
912
-
913
- ### "Invalid url to configure mqtt client!"
914
-
915
- **Cause:** The `url` option is empty when constructing an `MQTTClientHelper`. Throws an `ApplicationError` with status 500.
916
-
917
- **Fix:** Pass a valid MQTT broker URL:
918
-
919
- ```typescript
920
- // Wrong
921
- new MQTTClientHelper({ url: '', ... });
922
-
923
- // Correct
924
- new MQTTClientHelper({ url: 'mqtt://localhost:1883', ... });
925
- ```
926
-
927
- ### "MQTT Client is not available to subscribe topic!" / "MQTT Client is not available to publish message!"
928
-
929
- **Cause:** `subscribe()` or `publish()` was called before the MQTT client finished connecting, or after the client disconnected. Throws an `ApplicationError` with status 400.
930
-
931
- **Fix:** Wait for the `onConnect` callback before subscribing or publishing, or verify the client is connected:
142
+ import { MQTTClientHelper } from '@venizia/ignis-helpers/mqtt';
932
143
 
933
- ```typescript
934
144
  const client = new MQTTClientHelper({
935
- identifier: 'my-client',
145
+ identifier: 'sensor-client',
936
146
  url: 'mqtt://localhost:1883',
937
147
  options: {},
938
- onConnect: () => {
939
- // Safe to subscribe/publish here
940
- client.subscribe({ topics: ['my/topic'] });
941
- },
942
- onMessage: ({ topic, message }) => { /* ... */ },
148
+ onConnect: () => client.subscribe({ topics: ['sensors/temperature'] }),
149
+ onMessage: ({ topic, message }) => console.log(topic, message.toString()),
943
150
  });
944
- ```
945
-
946
- ### Elements not processing in In-Memory Queue
947
-
948
- **Cause:** Multiple possible reasons why `onMessage` is never called.
949
151
 
950
- **Checklist:**
951
- - Verify `onMessage` callback is provided -- the generator logs a warning and exits if missing
952
- - Check if the queue is locked -- call `unlock({ shouldProcessNextElement: true })` to resume
953
- - Check if `autoDispatch` is `false` -- call `nextMessage()` manually after each `enqueue()`
954
- - Check if the queue is settled -- a settled queue rejects new elements; create a new `QueueHelper` instance
955
-
956
- ### "Queue was SETTLED | No more element acceptable"
957
-
958
- **Cause:** `enqueue()` was called after `settle()` or `close()`.
959
-
960
- **Fix:** Create a new `QueueHelper` instance if you need to continue processing:
961
-
962
- ```typescript
963
- queue.close();
964
-
965
- // Start a new queue for further work
966
- const newQueue = new QueueHelper<string>({
967
- identifier: 'task-queue-v2',
968
- onMessage: async ({ queueElement }) => { /* ... */ },
969
- });
152
+ await client.publish({ topic: 'sensors/temperature', message: '23.5' });
970
153
  ```
971
154
 
972
- ## See Also
155
+ ## See also
156
+
157
+ - [Full reference](/extensions/helpers/queue/reference) - every option table, method signature, and the in-memory state machine in full
158
+ - [Redis Helper](/extensions/helpers/redis/) - `BullMQHelper`'s connection backend
159
+ - [Kafka Helpers](/extensions/helpers/kafka/) - the fourth queueing backend, documented separately
973
160
 
974
- - **Other Helpers:**
975
- - [Helpers Index](../index) -- All available helpers
976
- - [Cron Helper](../cron/) -- Scheduled tasks with cron expressions
977
- - [Redis Helper](../redis/) -- Redis connection management (required for BullMQ)
161
+ **Files:**
978
162
 
979
- - **External Resources:**
980
- - [BullMQ Documentation](https://docs.bullmq.io/) -- BullMQ queue library
981
- - [MQTT.js](https://github.com/mqttjs/MQTT.js) -- MQTT client library
982
- - [@platformatic/kafka](https://github.com/platformatic/kafka) -- Kafka client library
163
+ - [`packages/helpers/src/modules/queue/bullmq/helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/queue/bullmq/helper.ts) - `BullMQHelper`
164
+ - [`packages/helpers/src/modules/queue/internal/sequential/helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/queue/internal/sequential/helper.ts) - `SequentialQueueHelper` (deprecated alias `QueueHelper`)
165
+ - [`packages/helpers/src/modules/queue/mqtt/helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/queue/mqtt/helper.ts) - `MQTTClientHelper`