@venizia/ignis-docs 0.2.0 → 0.2.1-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 (142) 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 +22 -11
  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 +26 -2
  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 +6 -2
  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 +182 -93
  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 +107 -322
  26. package/content/extensions/components/authentication/api.md +454 -603
  27. package/content/extensions/components/authentication/errors.md +121 -498
  28. package/content/extensions/components/authentication/index.md +88 -801
  29. package/content/extensions/components/authentication/usage.md +207 -956
  30. package/content/extensions/components/authorization/api.md +736 -656
  31. package/content/extensions/components/authorization/errors.md +168 -206
  32. package/content/extensions/components/authorization/index.md +82 -797
  33. package/content/extensions/components/authorization/usage.md +194 -527
  34. package/content/extensions/components/health-check.md +71 -243
  35. package/content/extensions/components/mail/api.md +504 -287
  36. package/content/extensions/components/mail/errors.md +73 -61
  37. package/content/extensions/components/mail/index.md +96 -467
  38. package/content/extensions/components/mail/usage.md +130 -172
  39. package/content/extensions/components/request-tracker.md +66 -173
  40. package/content/extensions/components/socket-io/api.md +195 -13
  41. package/content/extensions/components/socket-io/errors.md +3 -3
  42. package/content/extensions/components/socket-io/index.md +50 -337
  43. package/content/extensions/components/socket-io/usage.md +143 -26
  44. package/content/extensions/components/static-asset/api.md +410 -142
  45. package/content/extensions/components/static-asset/errors.md +110 -53
  46. package/content/extensions/components/static-asset/index.md +79 -608
  47. package/content/extensions/components/static-asset/usage.md +180 -300
  48. package/content/extensions/components/websocket/api.md +275 -399
  49. package/content/extensions/components/websocket/errors.md +47 -56
  50. package/content/extensions/components/websocket/index.md +74 -407
  51. package/content/extensions/components/websocket/usage.md +110 -341
  52. package/content/extensions/helpers/cron/index.md +51 -160
  53. package/content/extensions/helpers/crypto/index.md +62 -483
  54. package/content/extensions/helpers/crypto/reference.md +456 -0
  55. package/content/extensions/helpers/env/index.md +60 -178
  56. package/content/extensions/helpers/error/index.md +221 -207
  57. package/content/extensions/helpers/inversion/index.md +65 -556
  58. package/content/extensions/helpers/inversion/reference.md +522 -0
  59. package/content/extensions/helpers/kafka/admin.md +20 -1
  60. package/content/extensions/helpers/kafka/compile-binary.md +41 -35
  61. package/content/extensions/helpers/kafka/consumer.md +54 -20
  62. package/content/extensions/helpers/kafka/examples.md +21 -16
  63. package/content/extensions/helpers/kafka/index.md +80 -610
  64. package/content/extensions/helpers/kafka/producer.md +134 -5
  65. package/content/extensions/helpers/kafka/schema-registry.md +45 -70
  66. package/content/extensions/helpers/logger/hf-logger.md +193 -0
  67. package/content/extensions/helpers/logger/index.md +64 -563
  68. package/content/extensions/helpers/logger/pino.md +85 -0
  69. package/content/extensions/helpers/logger/reference.md +746 -0
  70. package/content/extensions/helpers/network/api.md +241 -195
  71. package/content/extensions/helpers/network/index.md +72 -530
  72. package/content/extensions/helpers/queue/index.md +72 -900
  73. package/content/extensions/helpers/queue/reference.md +467 -0
  74. package/content/extensions/helpers/redis/index.md +73 -645
  75. package/content/extensions/helpers/redis/reference.md +727 -0
  76. package/content/extensions/helpers/secrets/index.md +66 -0
  77. package/content/extensions/helpers/socket-io/api.md +305 -203
  78. package/content/extensions/helpers/socket-io/index.md +66 -432
  79. package/content/extensions/helpers/storage/api.md +564 -462
  80. package/content/extensions/helpers/storage/index.md +77 -573
  81. package/content/extensions/helpers/types/index.md +66 -499
  82. package/content/extensions/helpers/types/reference.md +650 -0
  83. package/content/extensions/helpers/uid/index.md +58 -227
  84. package/content/extensions/helpers/websocket/api.md +329 -216
  85. package/content/extensions/helpers/websocket/index.md +65 -503
  86. package/content/extensions/helpers/worker-thread/index.md +58 -396
  87. package/content/extensions/helpers/worker-thread/reference.md +428 -0
  88. package/content/guides/core-concepts/persistent/models.md +1 -1
  89. package/content/guides/core-concepts/persistent/search-typesense.md +3 -3
  90. package/content/guides/core-concepts/persistent/transactions.md +1 -1
  91. package/content/guides/core-concepts/secrets-vault.md +177 -0
  92. package/content/guides/core-concepts/services.md +1 -1
  93. package/content/guides/migrations/redis-helpers-migration.md +1 -1
  94. package/content/guides/migrations/unified-connectors-migration.md +2 -2
  95. package/content/guides/tutorials/ecommerce-api.md +3 -8
  96. package/content/references/base/application.md +1 -1
  97. package/content/references/base/connectors.md +79 -136
  98. package/content/references/base/datasources-reference.md +599 -0
  99. package/content/references/base/datasources.md +84 -444
  100. package/content/references/base/dependency-injection.md +17 -39
  101. package/content/references/base/filter-system/application-usage.md +69 -121
  102. package/content/references/base/filter-system/array-operators.md +12 -0
  103. package/content/references/base/filter-system/comparison-operators.md +12 -0
  104. package/content/references/base/filter-system/default-filter.md +136 -348
  105. package/content/references/base/filter-system/fields-order-pagination.md +38 -16
  106. package/content/references/base/filter-system/index.md +106 -257
  107. package/content/references/base/filter-system/json-filtering.md +12 -2
  108. package/content/references/base/filter-system/list-operators.md +16 -2
  109. package/content/references/base/filter-system/logical-operators.md +13 -0
  110. package/content/references/base/filter-system/null-operators.md +13 -0
  111. package/content/references/base/filter-system/pattern-matching.md +12 -0
  112. package/content/references/base/filter-system/quick-reference.md +11 -2
  113. package/content/references/base/filter-system/range-operators.md +12 -0
  114. package/content/references/base/filter-system/tips.md +70 -133
  115. package/content/references/base/filter-system/use-cases.md +156 -233
  116. package/content/references/base/middlewares.md +35 -21
  117. package/content/references/base/models-reference.md +886 -0
  118. package/content/references/base/models.md +80 -1452
  119. package/content/references/base/repositories/advanced.md +156 -192
  120. package/content/references/base/repositories/index.md +77 -650
  121. package/content/references/base/repositories/mixins.md +22 -18
  122. package/content/references/base/repositories/relations.md +123 -171
  123. package/content/references/base/repositories/soft-deletable.md +58 -56
  124. package/content/references/base/secrets.md +263 -0
  125. package/content/references/base/services.md +2 -2
  126. package/content/references/configuration/environment-variables.md +48 -4
  127. package/content/references/configuration/index.md +49 -31
  128. package/content/references/quick-reference.md +3 -16
  129. package/content/references/utilities/crypto.md +35 -76
  130. package/content/references/utilities/date.md +33 -73
  131. package/content/references/utilities/index.md +1 -1
  132. package/content/references/utilities/jsx-reference.md +298 -0
  133. package/content/references/utilities/jsx.md +82 -525
  134. package/content/references/utilities/module.md +29 -62
  135. package/content/references/utilities/parse.md +34 -64
  136. package/content/references/utilities/performance.md +33 -58
  137. package/content/references/utilities/promise.md +28 -62
  138. package/content/references/utilities/request.md +57 -218
  139. package/content/references/utilities/schema.md +43 -137
  140. package/content/references/utilities/statuses-reference.md +361 -0
  141. package/content/references/utilities/statuses.md +63 -667
  142. package/package.json +8 -8
@@ -1,982 +1,154 @@
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 give you background job processing with BullMQ, a dependency-free in-memory queue for single-process sequencing, and MQTT pub/sub for lightweight event fan-out.
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.** `'queue'` exposes a `.queue` property (BullMQ `Queue`) for producers calling `.add()`; `'worker'` exposes a `.worker` property (BullMQ `Worker`) driven by your `onWorkerData` callback.
55
+ - **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 the caller's client directly.
56
+ - **`SequentialQueueHelper` runs one element at a time.** A `WAITING -> PROCESSING -> WAITING` loop driven by `onMessage`. `lock()` diverts the loop to `LOCKED` (elements still enqueue, nothing processes until `unlock()`); `settle()`/`close()` moves it to the terminal `SETTLED` state once the queue drains.
364
57
 
365
- const schemaRegistry = KafkaSchemaRegistryHelper.newInstance({
366
- url: 'http://localhost:8081',
367
- });
58
+ Full option tables, the complete state machine, and `HfQueueHelper` (the low-level FIFO primitive underneath) are in the [Full reference](/extensions/helpers/queue/reference).
368
59
 
369
- const producer = KafkaProducerHelper.newInstance({
370
- bootstrapBrokers: ['127.0.0.1:29092'],
371
- clientId: 'my-producer',
372
- registry: schemaRegistry.getRegistry(),
373
- });
374
- ```
60
+ ## Common tasks
375
61
 
376
- #### IKafkaSchemaRegistryOptions
377
-
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. |
385
-
386
- ## Usage
387
-
388
- ### BullMQ -- Adding Jobs
389
-
390
- When created with `role: 'queue'`, the helper exposes a `queue` property (a BullMQ `Queue` instance) for adding jobs.
62
+ ### Enqueue a job from a producer
391
63
 
392
64
  ```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
65
  await producer.queue.add('send-reset', { email: 'user@example.com', token: 'abc123' });
403
66
  ```
404
67
 
405
- > [!TIP]
406
- > You can also use the static factory method: `BullMQHelper.newInstance({ ... })` which is equivalent to `new BullMQHelper({ ... })`.
68
+ Jobs default to `removeOnComplete: true, removeOnFail: true` - BullMQ does not retain job records after they finish.
407
69
 
408
- #### Default Job Options
70
+ ### Process jobs with a worker
409
71
 
410
- Jobs are created with these defaults:
72
+ `numberOfWorker` sets concurrency; `onWorkerDataFail` receives the job (possibly `undefined`) and the error.
411
73
 
412
74
  ```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 }>({
75
+ const worker = BullMQHelper.newInstance({
425
76
  queueName: 'email-queue',
426
- identifier: 'email-consumer',
77
+ identifier: 'email-worker',
427
78
  role: 'worker',
428
- redisConnection: redisHelper,
79
+ redisConnection: redis,
429
80
  numberOfWorker: 3,
430
- lockDuration: 10 * 60 * 1000, // 10 minutes
431
- onWorkerData: async (job) => {
81
+ onWorkerData: async job => {
432
82
  await sendEmail(job.data.email);
433
83
  return { status: 'sent' };
434
84
  },
435
- onWorkerDataCompleted: async (job, result) => {
436
- console.log(`Job ${job.id} done:`, result);
437
- },
438
85
  onWorkerDataFail: async (job, error) => {
439
86
  console.error(`Job ${job?.id} failed:`, error.message);
440
87
  },
441
88
  });
442
89
  ```
443
90
 
444
- If `onWorkerData` is not provided, the worker logs the job's `id`, `name`, and `data` at the info level.
91
+ ### The Redis connection requirement
445
92
 
446
- ### BullMQ -- Redis Cluster
93
+ Pass an `IRedisHelper` instance, not a raw ioredis client - `BullMQHelper` calls `redisConnection.duplicateClient()` internally.
447
94
 
448
- When using Redis Cluster with BullMQ, use `RedisClusterHelper`. Set `maxRetriesPerRequest: null` inside `clusterOptions.redisOptions` -- this is **required** by BullMQ.
95
+ | Redis helper | Sets `maxRetriesPerRequest: null`? |
96
+ |--------------|-------------------------------------|
97
+ | `RedisSingleHelper` | Automatically |
98
+ | `RedisSentinelHelper` | Automatically |
99
+ | `RedisClusterHelper` | No - set it yourself, BullMQ requires it |
449
100
 
450
101
  ```typescript
451
102
  import { RedisClusterHelper } from '@venizia/ignis-helpers';
452
- import { BullMQHelper } from '@venizia/ignis-helpers/bullmq';
453
103
 
454
- const redisHelper = new RedisClusterHelper({
104
+ const clusterRedis = new RedisClusterHelper({
455
105
  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
- ],
106
+ nodes: [{ host: 'node1.redis.example.com', port: 6379 }],
461
107
  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
108
+ redisOptions: { maxRetriesPerRequest: null }, // required by BullMQ
479
109
  },
480
110
  });
481
111
  ```
482
112
 
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.
113
+ ### In-memory queue for single-process sequencing
497
114
 
498
115
  ```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
- ```
116
+ import { SequentialQueueHelper } from '@venizia/ignis-helpers';
508
117
 
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();
572
- },
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
- });
586
- ```
587
-
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.
599
-
600
- ```typescript
601
- consumer.startLagMonitoring({
602
- topics: ['orders'],
603
- interval: 30_000, // Default: 30 seconds
604
- });
605
-
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 }>({
118
+ const queue = new SequentialQueueHelper<{ task: string }>({
692
119
  identifier: 'task-processor',
693
120
  onMessage: async ({ queueElement }) => {
694
- console.log('Processing:', queueElement.payload.task);
695
121
  await performTask(queueElement.payload);
696
122
  },
697
123
  });
698
124
 
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 });
125
+ await queue.enqueue({ task: 'resize-image' });
702
126
  ```
703
127
 
704
- #### Manual Dispatch
705
-
706
- Set `autoDispatch: false` to control when processing begins. Call `nextMessage()` to trigger processing of the next element.
128
+ ### MQTT publish and subscribe
707
129
 
708
130
  ```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 });
767
- ```
768
-
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`:
890
-
891
- ```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:
131
+ import { MQTTClientHelper } from '@venizia/ignis-helpers/mqtt';
932
132
 
933
- ```typescript
934
133
  const client = new MQTTClientHelper({
935
- identifier: 'my-client',
134
+ identifier: 'sensor-client',
936
135
  url: 'mqtt://localhost:1883',
937
136
  options: {},
938
- onConnect: () => {
939
- // Safe to subscribe/publish here
940
- client.subscribe({ topics: ['my/topic'] });
941
- },
942
- onMessage: ({ topic, message }) => { /* ... */ },
137
+ onConnect: () => client.subscribe({ topics: ['sensors/temperature'] }),
138
+ onMessage: ({ topic, message }) => console.log(topic, message.toString()),
943
139
  });
944
- ```
945
-
946
- ### Elements not processing in In-Memory Queue
947
-
948
- **Cause:** Multiple possible reasons why `onMessage` is never called.
949
140
 
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
- });
141
+ await client.publish({ topic: 'sensors/temperature', message: '23.5' });
970
142
  ```
971
143
 
972
- ## See Also
144
+ ## See also
145
+
146
+ - [Full reference](/extensions/helpers/queue/reference) - every option table, method signature, and the in-memory state machine in full
147
+ - [Redis Helper](/extensions/helpers/redis/) - `BullMQHelper`'s connection backend
148
+ - [Kafka Helpers](/extensions/helpers/kafka/) - the fourth queueing backend, documented separately
973
149
 
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)
150
+ **Files:**
978
151
 
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
152
+ - [`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`
153
+ - [`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`)
154
+ - [`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`