runmq 1.0.2 → 1.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 CHANGED
@@ -1,21 +1,31 @@
1
- # RunMQ
1
+ <div align="center">
2
+ <img width="1479" height="612" alt="RunMQ-logo (4)" src="https://github.com/user-attachments/assets/50dc9187-26f9-4073-979b-31601c652e1f" />
3
+ <a href="https://badge.fury.io/js/runmq.svg">
4
+ <img src="https://badge.fury.io/js/runmq.svg"/>
5
+ </a>
6
+ <a href="https://github.com/semantic-release/semantic-release">
7
+ <img src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg"/>
8
+ </a>
9
+ </div>
2
10
 
3
- RunMQ is a reliable message queue library for Node.js built on top of RabbitMQ. Supports async background processing and event-driven messaging for microservices, with automatic retries, schema validation, and DLQ.
4
11
 
5
- RunMQ can be used to implement multiple messaging or jobs processing patterns:
6
- - **Event Bus** for event-driven architectures, where multiple services independently react to the same events
7
- - **Job Queue** for async background task processing
12
+ <b>RunMQ</b> is a high-performance message queue library for <b>Node.js</b>, built on top of <b>RabbitMQ</b>’s rock-solid messaging guarantees.
13
+
14
+ It combines RabbitMQ’s proven reliability with a modern developer experience — offering simple APIs, built-in fault tolerance, and seamless scaling for distributed systems.
15
+
16
+ Whether you’re running <b>background jobs</b>, designing an <b>event-driven architecture</b>, or managing a <b>pub/sub event bus</b>, RunMQ provides everything you need — all in a <b>lightweight package</b> with a <b>simple DX</b>, <b>without the hassle of managing everything on your own</b>.
17
+
8
18
 
9
19
  ## Features
10
20
 
11
- - **Automatic Connection Management**: Built-in retry logic with configurable attempts and delays
12
- - **Message Processing with Retries**: Automatic retry mechanism for failed messages with configurable retry delays
13
- - **Dead Letter Queue (DLQ) Support**: Failed messages automatically move to DLQ after exhausting retry attempts
14
- - **Isolated Queues**: Each processor maintains its own queue and DLQ, ensuring complete isolation between services
15
- - **Schema Validation**: Optional message validation using JSON Schema (AJV)
16
- - **Concurrent Processing**: Support for multiple concurrent consumers per queue
17
- - **Correlation ID Support**: Built-in correlation ID generation and tracking for distributed tracing
18
- - **Custom Logging**: Pluggable logging interface with default console logger
21
+ - **Reliable Message Processing with Retries**: Automatically retries failed messages with configurable delays and retry limits.
22
+ - **Dead Letter Queue (DLQ) Support**: Failed messages are seamlessly routed to a DLQ after all retry attempts are exhausted.
23
+ - **Pub/Sub with Atomic Delivery**: Publish a message once, and all subscribed consumers receive it atomically, without the need to publish multiple times.
24
+ - **Isolated Queues per Processor**: Each processor gets its own dedicated queue and DLQ, ensuring full isolation and predictable behavior across services.
25
+ - **Schema Validation**: Optional JSON Schema validation powered by AJV for safer message handling and data integrity.
26
+ - **Concurrent Consumers**: Scale either horizontally (multiple instances) or vertically (multiple consumers per queue, leveraging RabbitMQ prefetch) to maximize throughput and efficiency.
27
+ - **RabbitMQ Durability & Acknowledgements**: Leverages RabbitMQ’s persistent storage and acknowledgment model to guarantee at-least-once delivery, even across restarts and failures.
28
+ - **Custom Logging**: Plug in your own logger or use the default console logger for full control over message visibility.
19
29
 
20
30
  ## Installation
21
31
 
@@ -23,270 +33,129 @@ RunMQ can be used to implement multiple messaging or jobs processing patterns:
23
33
  npm install runmq
24
34
  ```
25
35
 
26
- ## Architecture Overview
27
-
28
- RunMQ can be used to implement various messaging patterns. Here are two common architectures:
29
-
30
- ### 1. Event-Driven Architecture (Event Bus Pattern)
31
-
32
- In this pattern, multiple processors (or services) subscribe to the same event topic. Each processor gets its own isolated queue and DLQ, enabling true microservices autonomy.
33
-
34
- ```
35
- Publisher → Topic (user.created)
36
- ├→ Queue: emailService → DLQ: emailService_dlq
37
- ├→ Queue: analyticsService → DLQ: analyticsService_dlq
38
- └→ Queue: notificationService → DLQ: notificationService_dlq
39
- ```
40
-
41
- **Key Benefits:**
42
- - Services remain independent and isolated
43
- - Each service can fail/retry without affecting others
44
- - Easy to add new services or processors by subscribing to existing topics
45
- - Scalable with multiple concurrent workers
46
-
47
- ### 2. Background Processing Pattern
36
+ ## Quick Start
48
37
 
49
- RunMQ can also be used as a job queue for background processing tasks. A single worker service processes jobs from a dedicated queue with retries and DLQ support.
38
+ ### Initialize RunMQ
39
+ The first step is to connect to RabbitMQ
50
40
 
51
- ```
52
- Publisher Topic (email.send) → Queue: emailWorker → DLQ: emailWorker_dlq
41
+ ```typescript
42
+ const runMQ = await RunMQ.start({
43
+ url: 'amqp://localhost:5672',
44
+ reconnectDelay: 5000, // Optional, default: 5000ms
45
+ maxReconnectAttempts: 5, // Optional, default: 5
46
+ management: {
47
+ url: "http://localhost:15673/",
48
+ username: "guest",
49
+ password: "guest"
50
+ };
51
+ });
53
52
  ```
54
53
 
55
- **Key Benefits:**
56
- - Simple async job processing
57
- - Automatic retries for failed jobs
58
- - Scalable with multiple concurrent workers
59
- - Dead letter queue for failed jobs
54
+ #### Notes:
55
+ - `reconnectDelay` defines the wait time between reconnection attempts.
56
+ - `maxReconnectAttempts` limits the number of retries when RabbitMQ is unavailable.
57
+ - Management configuration is optional but **highly recommended** to enables dynamic TTL via RabbitMQ policies; otherwise, RunMQ uses queue-based TTL.
60
58
 
61
- ## Quick Start
59
+ ### Processing side
62
60
 
63
- ### Basic Setup
61
+ It’s important that processors run before publishing messages, because queues are created internally when a consumer starts for the first time.
64
62
 
65
63
  ```typescript
66
64
  import { RunMQ } from 'runmq';
67
65
 
68
- // 1. Initialize RunMQ
69
- const runMQ = await RunMQ.start({
70
- url: 'amqp://localhost:5672',
71
- reconnectDelay: 5000, // optional, default: 5000ms
72
- maxReconnectAttempts: 5 // optional, default: 5
73
- });
74
-
75
- // 2. Process messages (create a consumer)
66
+ // Processor 1: Email Service
76
67
  await runMQ.process('user.created', {
77
- name: 'emailService', // Unique processor name (creates isolated queue)
78
- consumersCount: 2, // Number of concurrent workers
79
- attempts: 3, // Try processing a message up to 3 times
80
- attemptsDelay: 2000 // Wait 2 seconds between retries
68
+ name: 'emailService', // Unique processor name (creates an isolated queue)
69
+ consumersCount: 2, // Process up to 2 messages concurrently
70
+ attempts: 3, // Retry failed messages up to 3 times
71
+ attemptsDelay: 2000 // Wait 2 seconds between retries
81
72
  }, async (message) => {
82
- // Your processing logic here
83
- console.log('Received:', message.message);
73
+ console.log('EmailService received:', message.message);
84
74
  await sendEmail(message.message);
85
75
  });
86
76
 
87
- // 3. Publish messages
88
- runMQ.publish('user.created', {
89
- userId: '123',
90
- email: 'user@example.com',
91
- name: 'John Doe'
77
+ // Processor 2: SMS Service
78
+ await runMQ.process('user.created', {
79
+ name: 'smsService', // Unique processor name (separate queue)
80
+ consumersCount: 1, // Process 1 message at a time
81
+ attempts: 5, // Retry failed messages up to 5 times
82
+ attemptsDelay: 1000, // Wait 1 second between retries,
83
+ usePoliciesForDelay: true // highly recommended, default is false
84
+ }, async (message) => {
85
+ console.log('SMSService received:', message.message);
86
+ await sendSMS(message.message);
92
87
  });
93
-
94
- // That's it! The message will be delivered to all processors subscribed to 'user.created'
95
88
  ```
96
89
 
97
- ## Event-Driven Architecture Example
98
-
99
- One of the most powerful patterns with RunMQ is the Event Bus pattern, where multiple services independently react to the same events.
100
- The main advantage is that each service has its own isolated queue and dead letter queue, allowing for true microservices autonomy
101
- Publishing a single message (event) results in multiple services receiving and processing it independently.
90
+ #### Notes:
91
+ - `name` is the unique identifier for each processor.
92
+ - RunMQ supports <b>Pub/Sub</b> out-of-the-box: multiple processors can consume the same message independently.
93
+ - Example: When a user is created, one processor can send an email verification while another sends an SMS.
94
+ - Each processor can have its own configuration for:
95
+ - `attempts` How many the message will be retried
96
+ - `attemptsDelay` The delay between attempts, and if management config is provided, it can be changed anytime!
97
+ - `consumersCount` The concurrency level, how many messages can be processed in the same time.
98
+ - `usePoliciesForDelay` Enable this to let RunMQ use policies for defining delay queue TTL. Highly recommended, as it allows you to adjust delay times dynamically without re-declaring queues.
102
99
 
103
- ### Scenario: User Registration System
104
-
105
- When a user registers, multiple services need to react independently.
100
+ ### Publishing side
106
101
 
107
102
  ```typescript
108
- import { RunMQ, RunMQMessage } from 'runmq';
109
-
110
- interface UserCreatedEvent {
111
- userId: string;
112
- email: string;
113
- name: string;
114
- createdAt: string;
115
- }
116
-
117
- // Initialize RunMQ in each service
118
- const runMQ = await RunMQ.start({
119
- url: 'amqp://localhost:5672'
120
- });
121
-
122
- // ============================================
123
- // SERVICE 1: Email Service
124
- // ============================================
125
- await runMQ.process<UserCreatedEvent>('user.created', {
126
- name: 'emailService', // Creates queue: emailService
127
- consumersCount: 2,
128
- attempts: 3,
129
- attemptsDelay: 2000
130
- }, async (message: RunMQMessage<UserCreatedEvent>) => {
131
- console.log(`[Email Service] Sending welcome email to ${message.message.email}`);
132
- await sendWelcomeEmail(message.message);
133
- });
134
-
135
- // ============================================
136
- // SERVICE 2: Analytics Service
137
- // ============================================
138
- await runMQ.process<UserCreatedEvent>('user.created', {
139
- name: 'analyticsService', // Creates queue: analyticsService
140
- consumersCount: 1,
141
- attempts: 3
142
- }, async (message: RunMQMessage<UserCreatedEvent>) => {
143
- console.log(`[Analytics] Recording user registration for ${message.message.userId}`);
144
- await trackUserRegistration(message.message);
145
- });
146
-
147
- // ============================================
148
- // SERVICE 3: Notification Service
149
- // ============================================
150
- await runMQ.process<UserCreatedEvent>('user.created', {
151
- name: 'notificationService', // Creates queue: notificationService
152
- consumersCount: 3,
153
- attempts: 5,
154
- attemptsDelay: 1000
155
- }, async (message: RunMQMessage<UserCreatedEvent>) => {
156
- console.log(`[Notifications] Sending push notification to ${message.message.userId}`);
157
- await sendPushNotification(message.message);
158
- });
159
-
160
- // ============================================
161
- // PUBLISHER: User Registration Handler
162
- // ============================================
163
- // When a user registers, publish one event
164
103
  runMQ.publish('user.created', {
165
- userId: 'user-123',
166
- email: 'john@example.com',
167
- name: 'John Doe',
168
- createdAt: new Date().toISOString()
104
+ userId: '123',
105
+ email: 'user@example.com',
106
+ name: 'John Doe'
169
107
  });
170
-
171
- // All three services receive the event independently!
172
108
  ```
173
109
 
174
- ### Adding a New Processor
175
-
176
- Want to add a new service? Just subscribe to existing events:
110
+ Each processor receives the message independently without needing multiple publishes.
177
111
 
178
- ```typescript
179
- // NEW SERVICE 4: CRM Sync Service
180
- await runMQ.process<UserCreatedEvent>('user.created', {
181
- name: 'crmSyncService', // Creates new isolated queue
182
- consumersCount: 1,
183
- attempts: 3
184
- }, async (message: RunMQMessage<UserCreatedEvent>) => {
185
- console.log(`[CRM] Syncing user to CRM: ${message.message.userId}`);
186
- await syncToCRM(message.message);
187
- });
112
+ <br>
188
113
 
189
- // This new service automatically receives all future user.created events
190
- // No changes needed to existing services!
191
- ```
114
+ ## Patterns in details
192
115
 
193
- ## Job Queue Pattern Example
116
+ RunMQ can be used to implement various messaging patterns. Two common architectures are:
194
117
 
195
- ### Scenario: Background Email Processing
118
+ ### 1. Event-Driven Architecture (Event Bus Pattern)
196
119
 
197
- The other common pattern is using RunMQ as a job queue for background processing tasks.
198
- Where there's a publisher queuing jobs, and a worker service processing them asynchronously with retries and DLQ support.
120
+ The Event Bus pattern allows multiple services (or processors) to react independently to the same events. Each service has its own queue and DLQ, ensuring full isolation and autonomy.
199
121
 
200
- ```typescript
201
- import { RunMQ, RunMQMessage } from 'runmq';
122
+ ```
123
+ Publisher Topic (user.created)
124
+ ├→ Queue: emailService → DLQ: emailService_dlq
125
+ ├→ Queue: analyticsService → DLQ: analyticsService_dlq
126
+ └→ Queue: notificationService → DLQ: notificationService_dlq
127
+ ```
202
128
 
203
- interface EmailJob {
204
- to: string;
205
- subject: string;
206
- body: string;
207
- attachments?: string[];
208
- }
129
+ **Key insights:**
130
+ - Publishing a single message delivers it to all processors subscribed to the topic.
131
+ - Each processor can have its own retry policy, consumer count, and delay configuration.
132
+ - Easily add new services by subscribing to existing topics.
133
+ - Dead Letter Queues allow failed messages to be captured without affecting other services.
134
+ - This architecture ensures microservices autonomy, reliability, and scalability.
135
+ - Schema validation ensures that only valid messages are processed; invalid messages can be routed to the DLQ automatically.
209
136
 
210
- const runMQ = await RunMQ.start({
211
- url: 'amqp://localhost:5672'
212
- });
137
+ ### 2. Background Processing Pattern
213
138
 
214
- // ============================================
215
- // WORKER: Email Processing Service
216
- // ============================================
217
- await runMQ.process<EmailJob>('email.send', {
218
- name: 'emailWorker', // Single queue for job processing
219
- consumersCount: 5, // 5 concurrent workers
220
- attempts: 3,
221
- attemptsDelay: 5000,
222
- messageSchema: {
223
- type: 'ajv',
224
- schema: {
225
- type: 'object',
226
- properties: {
227
- to: { type: 'string', format: 'email' },
228
- subject: { type: 'string' },
229
- body: { type: 'string' },
230
- attachments: {
231
- type: 'array',
232
- items: { type: 'string' }
233
- }
234
- },
235
- required: ['to', 'subject', 'body']
236
- },
237
- failureStrategy: 'dlq'
238
- }
239
- }, async (message: RunMQMessage<EmailJob>) => {
240
- console.log(`[Worker] Sending email to ${message.message.to}`);
241
-
242
- await sendEmail({
243
- to: message.message.to,
244
- subject: message.message.subject,
245
- body: message.message.body,
246
- attachments: message.message.attachments
247
- });
248
-
249
- console.log(`[Worker] Email sent successfully to ${message.message.to}`);
250
- });
139
+ RunMQ can also act as a job queue for background tasks. A worker service processes jobs from a dedicated queue with retries and DLQ support.
251
140
 
252
- // ============================================
253
- // PUBLISHER: API Endpoint
254
- // ============================================
255
- // Your API can now queue emails for background processing
256
- app.post('/api/send-email', async (req, res) => {
257
- const { to, subject, body } = req.body;
258
-
259
- // Queue the job - returns immediately
260
- runMQ.publish('email.send', {
261
- to,
262
- subject,
263
- body,
264
- attachments: []
265
- });
266
-
267
- res.json({ status: 'queued' });
268
- });
141
+ ```
142
+ Publisher → Topic (email.send) → Queue: emailWorker → DLQ: emailWorker_dlq
269
143
  ```
270
144
 
271
- ### Job Processing Flow
145
+ **Key insights:**
146
+ - Dead Letter Queues allow failed messages to be captured without affecting other services.
147
+ - Schema validation ensures that only valid messages are processed; invalid messages can be routed to the DLQ automatically.
148
+ - Multiple concurrent workers can process jobs in parallel for high throughput.
272
149
 
273
- ```
274
- API Request → Publish Job → Queue (emailWorker)
275
-
276
- 5 Concurrent Workers
277
-
278
- [Success] or [Try processing for 3 times]
279
-
280
- [Final Failure] → DLQ (emailWorker_dlq)
281
- ```
150
+ <br>
282
151
 
283
- ## Features in Detail
152
+ ## Advanced Features
284
153
 
285
154
  ### Schema Validation
286
155
 
287
- RunMQ supports JSON schema validation to ensure message integrity, so only valid messages are passed to your processors
288
- Currently, only AJV is supported for schema validation, with a single failure strategy of sending invalid messages to the DLQ in the meantime.
289
- if the schema validation fails, the message is sent directly to the DLQ without being processed.
156
+ RunMQ supports JSON Schema validation to ensure message integrity, so only valid messages are passed to your processors.
157
+ - Currently, AJV is supported for schema validation.
158
+ - Invalid messages are sent directly to the DLQ without being sent to the processor.
290
159
 
291
160
  ```typescript
292
161
  const orderSchema = {
@@ -326,96 +195,108 @@ await runMQ.process('order.placed', {
326
195
  await processOrder(message.message);
327
196
  });
328
197
  ```
198
+ **Key insights:**
199
+ - Schema validation enforces message correctness before processing, reducing runtime errors.
200
+ - Only messages matching the schema reach your business logic.
201
+ - DLQ ensures that invalid messages are captured and can be inspected later.
329
202
 
330
- ### Queue Isolation and Naming
203
+ ### Policies for delay between attempts
331
204
 
332
- **Important:** Each processor creates an isolated queue based on its `name` parameter:
205
+ RunMQ can leverage RabbitMQ policies to manage the delay between attempts, it's not used by default, however it's <b>highly recommended</b> to enable it.
333
206
 
334
- - Queue name: `{processor.name}`
335
- - DLQ name: `{processor.name}_dlq`
207
+ - When `usePoliciesForDelay` is enabled, RunMQ creates delay queues with TTL configured via RabbitMQ policies rather than hard-coding TTL in the queue itself.
208
+ - Hard-coding the TTL requires manual queue re-declaration to change delays, which can involve deleting queues - making it cumbersome and error-prone.
209
+ - Policies allow dynamic updates to the TTL without recreating queues — you can change attempts delay anytime, and RunMQ will take care of the rest.
336
210
 
337
- This ensures:
338
- - Processors can't interfere with each other
339
- - Each processor controls its own retry logic
340
- - Failed messages are isolated per processor
341
- - ✅ Easy to monitor and debug per-processor queues
342
-
343
- Example:
344
- ```typescript
345
- // Creates queue: userEmailService and userEmailService_dlq
346
- await runMQ.process('user.created', { name: 'userEmailService', ... }, handler);
347
-
348
- // Creates queue: userAnalytics and userAnalytics_dlq
349
- await runMQ.process('user.created', { name: 'userAnalytics', ... }, handler);
350
- ```
211
+ #### Benefits
212
+ - Flexible and easy management of retry delays
213
+ - Reduces operational overhead
214
+ - Fully compatible with RunMQ’s retry and DLQ mechanisms
351
215
 
352
216
  ### Custom Logger
353
217
 
354
- The default loger uses console, but you can implement your own logger by implementing the `RunMQLogger` interface:
218
+ RunMQ uses a default console logger, but you can provide a custom logger by implementing the RunMQLogger interface:
355
219
 
356
220
  ```typescript
357
221
  import { RunMQLogger } from 'runmq';
358
222
 
359
223
  class CustomLogger implements RunMQLogger {
360
224
  log(message: string): void {
361
- // Your logging implementation
225
+ // Custom info logging
362
226
  }
363
227
 
364
228
  error(message: string, error?: any): void {
365
- // Your error logging implementation
229
+ // Custom error logging
366
230
  }
367
231
  }
368
232
 
233
+ // Pass the custom logger when starting RunMQ
369
234
  const runMQ = await RunMQ.start(config, new CustomLogger());
370
235
  ```
371
236
 
372
- ## Configuration
237
+ **Key insights:**
238
+ - Custom loggers allow integration with centralized logging systems (e.g., Winston, Bunyan, Datadog).
239
+ - Both info and error methods can be customized to suit your monitoring strategy.
240
+
241
+ <br>
242
+
243
+ ## ⚙️ Types
373
244
 
374
245
  ### Connection Configuration
375
246
 
376
- ```typescript
377
- interface RunMQConnectionConfig {
378
- url: string; // The URL of the RabbitMQ server.
379
- reconnectDelay?: number; // The delay in milliseconds before attempting to reconnect after a disconnection (default: 5000)
380
- maxReconnectAttempts?: number; // Maximum reconnection attempts (default: 5)
381
- }
382
- ```
247
+ | Property | Type | Default | Description |
248
+ |----------|------|---------|-------------|
249
+ | `url` | `string` | — | The URL of the RabbitMQ server. |
250
+ | `reconnectDelay` | `number` | `5000` | Delay in milliseconds before attempting to reconnect after a disconnection. |
251
+ | `maxReconnectAttempts` | `number` | `5` | Maximum number of reconnection attempts. |
252
+ | `management` | `ManagementConfiguration` | — | RabbitMQ management API configuration. |
253
+
254
+ ---
255
+
256
+ ### Management configuration
257
+
258
+ | Property | Type | Default | Description |
259
+ |----------|------|---------|-------------|
260
+ | `url` | `string` | `"http://localhost:15672/"` | The URL of the RabbitMQ management API. |
261
+ | `username` | `string` | `"guest"` | Username for management API authentication. |
262
+ | `password` | `string` | `"guest"` | Password for management API authentication. |
263
+
264
+ ---
383
265
 
384
266
  ### Processor Configuration
385
267
 
386
- ```typescript
387
- interface RunMQProcessorConfiguration {
388
- name: string; // The name of the processor, used to create isolated queues for each processor.
389
- consumersCount: number; // The number of concurrent consumers to run for this processor.
390
- attempts?: number; // The maximum number attempts processing a message, default is 1 attempt.
391
- attemptsDelay?: number; // The delay in milliseconds between attempts.
392
- messageSchema?: MessageSchema; // The schema configuration for message validation.
393
- }
394
- ```
268
+ | Property | Type | Default | Description |
269
+ |----------|------|---------|-------------|
270
+ | `name` | `string` | — | Unique name of the processor, used to create isolated queues. |
271
+ | `consumersCount` | `number` | | Number of concurrent consumers for this processor. |
272
+ | `attempts` | `number` | `1` | Maximum attempts to process a message. |
273
+ | `attemptsDelay` | `number` | `1000` | Delay in milliseconds between attempts. |
274
+ | `messageSchema` | `MessageSchema` | | Optional schema configuration for message validation. |
275
+ | `usePoliciesForDelay` | `boolean` | false | Optional configuration to use Policies for attempts delay, highly recommended. |
276
+
277
+
278
+ ---
395
279
 
396
280
  ### Message Schema Configuration
397
281
 
398
- ```typescript
399
- interface MessageSchema {
400
- type: 'ajv'; // The type of schema used for validation (Currently only 'ajv').
401
- schema: any; // The schema definition of the chosen schemaType, used for validating messages.
402
- failureStrategy: 'dlq'; // The strategy to apply when schema validation fails (e.g., 'dlq').
403
- }
404
- ```
282
+ | Property | Type | Description |
283
+ |----------|------|-------------|
284
+ | `type` | `'ajv'` | Type of schema used for validation (currently only AJV supported). |
285
+ | `schema` | `any` | Schema definition for validating messages. |
286
+ | `failureStrategy` | `'dlq'` | Strategy applied when schema validation fails (e.g., move to DLQ). |
405
287
 
406
- ## Message Structure
288
+ ---
289
+
290
+ ## 📦 Message Structure
291
+
292
+ | Property | Type | Description |
293
+ |----------|------|-------------|
294
+ | `message` | `T` | Your message payload. |
295
+ | `meta.id` | `string` | Unique identifier of the message. |
296
+ | `meta.publishedAt` | `number` | Timestamp when the message was published. |
297
+ | `meta.correlationId` | `string` | Correlation identifier for tracing. |
407
298
 
408
- ```typescript
409
- interface RunMQMessageContent<T> {
410
- message: T; // Your message payload
411
- meta: {
412
- id: string; // The unique identifier of the message.
413
- publishedAt: number; // The timestamp when the message was published.
414
- correlationId: string; // The correlation identifier.
415
- }
416
- }
417
- ```
418
299
 
419
300
  ## License
420
301
 
421
- MIT
302
+ MIT