@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.
- package/README.md +14 -14
- package/content/best-practices/api-usage-examples.md +39 -19
- package/content/best-practices/architectural-patterns.md +22 -11
- package/content/best-practices/architecture-decisions.md +29 -16
- package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
- package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
- package/content/best-practices/code-style-standards/control-flow.md +33 -1
- package/content/best-practices/code-style-standards/documentation.md +28 -8
- package/content/best-practices/code-style-standards/function-patterns.md +15 -4
- package/content/best-practices/code-style-standards/index.md +7 -2
- package/content/best-practices/code-style-standards/naming-conventions.md +26 -2
- package/content/best-practices/code-style-standards/route-definitions.md +9 -5
- package/content/best-practices/code-style-standards/tooling.md +14 -1
- package/content/best-practices/code-style-standards/type-safety.md +39 -6
- package/content/best-practices/common-pitfalls.md +59 -35
- package/content/best-practices/contribution-workflow.md +6 -2
- package/content/best-practices/data-modeling.md +78 -62
- package/content/best-practices/deployment-strategies.md +56 -19
- package/content/best-practices/error-handling.md +182 -93
- package/content/best-practices/index.md +6 -0
- package/content/best-practices/performance-optimization.md +26 -13
- package/content/best-practices/security-guidelines.md +35 -9
- package/content/best-practices/testing-strategies.md +7 -2
- package/content/best-practices/troubleshooting-tips.md +27 -17
- package/content/extensions/components/api-reference.md +107 -322
- package/content/extensions/components/authentication/api.md +454 -603
- package/content/extensions/components/authentication/errors.md +121 -498
- package/content/extensions/components/authentication/index.md +88 -801
- package/content/extensions/components/authentication/usage.md +207 -956
- package/content/extensions/components/authorization/api.md +736 -656
- package/content/extensions/components/authorization/errors.md +168 -206
- package/content/extensions/components/authorization/index.md +82 -797
- package/content/extensions/components/authorization/usage.md +194 -527
- package/content/extensions/components/health-check.md +71 -243
- package/content/extensions/components/mail/api.md +504 -287
- package/content/extensions/components/mail/errors.md +73 -61
- package/content/extensions/components/mail/index.md +96 -467
- package/content/extensions/components/mail/usage.md +130 -172
- package/content/extensions/components/request-tracker.md +66 -173
- package/content/extensions/components/socket-io/api.md +195 -13
- package/content/extensions/components/socket-io/errors.md +3 -3
- package/content/extensions/components/socket-io/index.md +50 -337
- package/content/extensions/components/socket-io/usage.md +143 -26
- package/content/extensions/components/static-asset/api.md +410 -142
- package/content/extensions/components/static-asset/errors.md +110 -53
- package/content/extensions/components/static-asset/index.md +79 -608
- package/content/extensions/components/static-asset/usage.md +180 -300
- package/content/extensions/components/websocket/api.md +275 -399
- package/content/extensions/components/websocket/errors.md +47 -56
- package/content/extensions/components/websocket/index.md +74 -407
- package/content/extensions/components/websocket/usage.md +110 -341
- package/content/extensions/helpers/cron/index.md +51 -160
- package/content/extensions/helpers/crypto/index.md +62 -483
- package/content/extensions/helpers/crypto/reference.md +456 -0
- package/content/extensions/helpers/env/index.md +60 -178
- package/content/extensions/helpers/error/index.md +221 -207
- package/content/extensions/helpers/inversion/index.md +65 -556
- package/content/extensions/helpers/inversion/reference.md +522 -0
- package/content/extensions/helpers/kafka/admin.md +20 -1
- package/content/extensions/helpers/kafka/compile-binary.md +41 -35
- package/content/extensions/helpers/kafka/consumer.md +54 -20
- package/content/extensions/helpers/kafka/examples.md +21 -16
- package/content/extensions/helpers/kafka/index.md +80 -610
- package/content/extensions/helpers/kafka/producer.md +134 -5
- package/content/extensions/helpers/kafka/schema-registry.md +45 -70
- package/content/extensions/helpers/logger/hf-logger.md +193 -0
- package/content/extensions/helpers/logger/index.md +64 -563
- package/content/extensions/helpers/logger/pino.md +85 -0
- package/content/extensions/helpers/logger/reference.md +746 -0
- package/content/extensions/helpers/network/api.md +241 -195
- package/content/extensions/helpers/network/index.md +72 -530
- package/content/extensions/helpers/queue/index.md +72 -900
- package/content/extensions/helpers/queue/reference.md +467 -0
- package/content/extensions/helpers/redis/index.md +73 -645
- package/content/extensions/helpers/redis/reference.md +727 -0
- package/content/extensions/helpers/secrets/index.md +66 -0
- package/content/extensions/helpers/socket-io/api.md +305 -203
- package/content/extensions/helpers/socket-io/index.md +66 -432
- package/content/extensions/helpers/storage/api.md +564 -462
- package/content/extensions/helpers/storage/index.md +77 -573
- package/content/extensions/helpers/types/index.md +66 -499
- package/content/extensions/helpers/types/reference.md +650 -0
- package/content/extensions/helpers/uid/index.md +58 -227
- package/content/extensions/helpers/websocket/api.md +329 -216
- package/content/extensions/helpers/websocket/index.md +65 -503
- package/content/extensions/helpers/worker-thread/index.md +58 -396
- package/content/extensions/helpers/worker-thread/reference.md +428 -0
- package/content/guides/core-concepts/persistent/models.md +1 -1
- package/content/guides/core-concepts/persistent/search-typesense.md +3 -3
- package/content/guides/core-concepts/persistent/transactions.md +1 -1
- package/content/guides/core-concepts/secrets-vault.md +177 -0
- package/content/guides/core-concepts/services.md +1 -1
- package/content/guides/migrations/redis-helpers-migration.md +1 -1
- package/content/guides/migrations/unified-connectors-migration.md +2 -2
- package/content/guides/tutorials/ecommerce-api.md +3 -8
- package/content/references/base/application.md +1 -1
- package/content/references/base/connectors.md +79 -136
- package/content/references/base/datasources-reference.md +599 -0
- package/content/references/base/datasources.md +84 -444
- package/content/references/base/dependency-injection.md +17 -39
- package/content/references/base/filter-system/application-usage.md +69 -121
- package/content/references/base/filter-system/array-operators.md +12 -0
- package/content/references/base/filter-system/comparison-operators.md +12 -0
- package/content/references/base/filter-system/default-filter.md +136 -348
- package/content/references/base/filter-system/fields-order-pagination.md +38 -16
- package/content/references/base/filter-system/index.md +106 -257
- package/content/references/base/filter-system/json-filtering.md +12 -2
- package/content/references/base/filter-system/list-operators.md +16 -2
- package/content/references/base/filter-system/logical-operators.md +13 -0
- package/content/references/base/filter-system/null-operators.md +13 -0
- package/content/references/base/filter-system/pattern-matching.md +12 -0
- package/content/references/base/filter-system/quick-reference.md +11 -2
- package/content/references/base/filter-system/range-operators.md +12 -0
- package/content/references/base/filter-system/tips.md +70 -133
- package/content/references/base/filter-system/use-cases.md +156 -233
- package/content/references/base/middlewares.md +35 -21
- package/content/references/base/models-reference.md +886 -0
- package/content/references/base/models.md +80 -1452
- package/content/references/base/repositories/advanced.md +156 -192
- package/content/references/base/repositories/index.md +77 -650
- package/content/references/base/repositories/mixins.md +22 -18
- package/content/references/base/repositories/relations.md +123 -171
- package/content/references/base/repositories/soft-deletable.md +58 -56
- package/content/references/base/secrets.md +263 -0
- package/content/references/base/services.md +2 -2
- package/content/references/configuration/environment-variables.md +48 -4
- package/content/references/configuration/index.md +49 -31
- package/content/references/quick-reference.md +3 -16
- package/content/references/utilities/crypto.md +35 -76
- package/content/references/utilities/date.md +33 -73
- package/content/references/utilities/index.md +1 -1
- package/content/references/utilities/jsx-reference.md +298 -0
- package/content/references/utilities/jsx.md +82 -525
- package/content/references/utilities/module.md +29 -62
- package/content/references/utilities/parse.md +34 -64
- package/content/references/utilities/performance.md +33 -58
- package/content/references/utilities/promise.md +28 -62
- package/content/references/utilities/request.md +57 -218
- package/content/references/utilities/schema.md +43 -137
- package/content/references/utilities/statuses-reference.md +361 -0
- package/content/references/utilities/statuses.md +63 -667
- package/package.json +8 -8
|
@@ -1,982 +1,154 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
13
|
+
Create a Redis-backed producer and worker with `BullMQHelper`.
|
|
27
14
|
|
|
28
15
|
```typescript
|
|
29
|
-
|
|
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
|
-
|
|
19
|
+
const redis = new RedisSingleHelper({ name: 'queue-redis', host: 'localhost', port: 6379, password: 'secret' });
|
|
72
20
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
21
|
+
const producer = BullMQHelper.newInstance({
|
|
22
|
+
queueName: 'email-queue',
|
|
23
|
+
identifier: 'email-producer',
|
|
24
|
+
role: 'queue',
|
|
25
|
+
redisConnection: redis,
|
|
26
|
+
});
|
|
76
27
|
|
|
77
|
-
|
|
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 =
|
|
30
|
+
const worker = BullMQHelper.newInstance({
|
|
82
31
|
queueName: 'email-queue',
|
|
83
32
|
identifier: 'email-worker',
|
|
84
33
|
role: 'worker',
|
|
85
|
-
redisConnection:
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
363
|
-
|
|
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
|
-
|
|
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
|
-
|
|
370
|
-
bootstrapBrokers: ['127.0.0.1:29092'],
|
|
371
|
-
clientId: 'my-producer',
|
|
372
|
-
registry: schemaRegistry.getRegistry(),
|
|
373
|
-
});
|
|
374
|
-
```
|
|
60
|
+
## Common tasks
|
|
375
61
|
|
|
376
|
-
|
|
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
|
-
|
|
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
|
-
|
|
70
|
+
### Process jobs with a worker
|
|
409
71
|
|
|
410
|
-
|
|
72
|
+
`numberOfWorker` sets concurrency; `onWorkerDataFail` receives the job (possibly `undefined`) and the error.
|
|
411
73
|
|
|
412
74
|
```typescript
|
|
413
|
-
|
|
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-
|
|
77
|
+
identifier: 'email-worker',
|
|
427
78
|
role: 'worker',
|
|
428
|
-
redisConnection:
|
|
79
|
+
redisConnection: redis,
|
|
429
80
|
numberOfWorker: 3,
|
|
430
|
-
|
|
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
|
-
|
|
91
|
+
### The Redis connection requirement
|
|
445
92
|
|
|
446
|
-
|
|
93
|
+
Pass an `IRedisHelper` instance, not a raw ioredis client - `BullMQHelper` calls `redisConnection.duplicateClient()` internally.
|
|
447
94
|
|
|
448
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
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
|
-
>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: '
|
|
134
|
+
identifier: 'sensor-client',
|
|
936
135
|
url: 'mqtt://localhost:1883',
|
|
937
136
|
options: {},
|
|
938
|
-
onConnect: () => {
|
|
939
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
-
|
|
980
|
-
|
|
981
|
-
|
|
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`
|