chub-dev 0.1.0 → 0.1.2-beta.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 +55 -0
- package/bin/chub-mcp +2 -0
- package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
- package/dist/airtable/docs/database/python/DOC.md +1735 -0
- package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
- package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
- package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
- package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
- package/dist/asana/docs/tasks/DOC.md +1396 -0
- package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
- package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
- package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
- package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
- package/dist/auth0/docs/identity/python/DOC.md +1199 -0
- package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
- package/dist/aws/docs/s3/python/DOC.md +1807 -0
- package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
- package/dist/binance/docs/trading/python/DOC.md +1454 -0
- package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
- package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
- package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
- package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
- package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
- package/dist/clerk/docs/auth/python/DOC.md +274 -0
- package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
- package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
- package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
- package/dist/cohere/docs/llm/DOC.md +1335 -0
- package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
- package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
- package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
- package/dist/deepgram/docs/speech/python/DOC.md +685 -0
- package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
- package/dist/deepl/docs/translation/python/DOC.md +944 -0
- package/dist/deepseek/docs/llm/DOC.md +1220 -0
- package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
- package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
- package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
- package/dist/discord/docs/bot/python/DOC.md +1130 -0
- package/dist/elasticsearch/docs/search/DOC.md +1634 -0
- package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
- package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
- package/dist/firebase/docs/auth/DOC.md +1015 -0
- package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
- package/dist/gemini/docs/genai/python/DOC.md +555 -0
- package/dist/github/docs/octokit/DOC.md +1560 -0
- package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
- package/dist/google/docs/bigquery/python/DOC.md +1503 -0
- package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
- package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
- package/dist/huggingface/docs/transformers/DOC.md +948 -0
- package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
- package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
- package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
- package/dist/jira/docs/issues/python/DOC.md +1492 -0
- package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
- package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
- package/dist/landingai-ade/docs/api/DOC.md +620 -0
- package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
- package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
- package/dist/landingai-ade/skills/SKILL.md +489 -0
- package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
- package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
- package/dist/linear/docs/tracker/DOC.md +1554 -0
- package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
- package/dist/livekit/docs/realtime/python/DOC.md +163 -0
- package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
- package/dist/meilisearch/docs/search/DOC.md +1241 -0
- package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
- package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
- package/dist/mongodb/docs/atlas/DOC.md +2041 -0
- package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
- package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
- package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
- package/dist/okta/docs/identity/python/DOC.md +1401 -0
- package/dist/openai/docs/chat/javascript/DOC.md +407 -0
- package/dist/openai/docs/chat/python/DOC.md +568 -0
- package/dist/paypal/docs/checkout/DOC.md +278 -0
- package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
- package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
- package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
- package/dist/plaid/docs/banking/python/DOC.md +1203 -0
- package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
- package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
- package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
- package/dist/prisma/docs/orm/python/DOC.md +1317 -0
- package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
- package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
- package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
- package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
- package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
- package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
- package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
- package/dist/redis/docs/key-value/python/DOC.md +2054 -0
- package/dist/registry.json +2817 -0
- package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
- package/dist/resend/docs/email/DOC.md +1271 -0
- package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
- package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
- package/dist/search-index.json +1 -0
- package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
- package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
- package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
- package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
- package/dist/shopify/docs/storefront/DOC.md +457 -0
- package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
- package/dist/slack/docs/workspace/python/DOC.md +271 -0
- package/dist/square/docs/payments/javascript/DOC.md +1855 -0
- package/dist/square/docs/payments/python/DOC.md +1728 -0
- package/dist/stripe/docs/api/DOC.md +1727 -0
- package/dist/stripe/docs/payments/DOC.md +1726 -0
- package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
- package/dist/stytch/docs/auth/python/DOC.md +1962 -0
- package/dist/supabase/docs/client/DOC.md +1606 -0
- package/dist/twilio/docs/messaging/python/DOC.md +469 -0
- package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
- package/dist/vercel/docs/platform/DOC.md +1940 -0
- package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
- package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
- package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
- package/dist/zendesk/docs/support/python/DOC.md +2297 -0
- package/package.json +22 -6
- package/skills/get-api-docs/SKILL.md +84 -0
- package/src/commands/annotate.js +83 -0
- package/src/commands/build.js +12 -1
- package/src/commands/feedback.js +150 -0
- package/src/commands/get.js +83 -42
- package/src/commands/search.js +7 -0
- package/src/index.js +43 -17
- package/src/lib/analytics.js +90 -0
- package/src/lib/annotations.js +57 -0
- package/src/lib/bm25.js +170 -0
- package/src/lib/cache.js +69 -6
- package/src/lib/config.js +8 -3
- package/src/lib/identity.js +99 -0
- package/src/lib/registry.js +103 -20
- package/src/lib/telemetry.js +86 -0
- package/src/mcp/server.js +177 -0
- package/src/mcp/tools.js +251 -0
|
@@ -0,0 +1,1193 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: message-queue
|
|
3
|
+
description: "RabbitMQ amqplib coding guidelines for JavaScript/Node.js message broker interactions"
|
|
4
|
+
metadata:
|
|
5
|
+
languages: "javascript"
|
|
6
|
+
versions: "0.10.9"
|
|
7
|
+
updated-on: "2026-03-02"
|
|
8
|
+
source: maintainer
|
|
9
|
+
tags: "rabbitmq,queue,amqp,messaging,async"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# RabbitMQ amqplib Coding Guidelines (JavaScript/Node.js)
|
|
13
|
+
|
|
14
|
+
You are a RabbitMQ amqplib coding expert. Help me with writing code using RabbitMQ message broker via the official amqplib library.
|
|
15
|
+
|
|
16
|
+
## Golden Rule: Use the Correct and Current SDK
|
|
17
|
+
|
|
18
|
+
Always use the official amqplib library for all RabbitMQ (AMQP 0-9-1) interactions in Node.js.
|
|
19
|
+
|
|
20
|
+
- **Library Name:** amqplib
|
|
21
|
+
- **NPM Package:** `amqplib`
|
|
22
|
+
- **Current Version:** 0.10.9 or higher
|
|
23
|
+
- **Minimum Required Version:** 0.10.7+ (for RabbitMQ 4.1.0+ compatibility)
|
|
24
|
+
|
|
25
|
+
**Installation:**
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install amqplib
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**IMPORTANT:** Do not use the deprecated `amqp` or `node-amqp` packages. Always use `amqplib`.
|
|
32
|
+
|
|
33
|
+
**Import Patterns:**
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
// Callback API
|
|
37
|
+
const amqp = require('amqplib/callback_api');
|
|
38
|
+
|
|
39
|
+
// Promise/async-await API (recommended)
|
|
40
|
+
const amqp = require('amqplib');
|
|
41
|
+
|
|
42
|
+
// ES6 import
|
|
43
|
+
import amqp from 'amqplib';
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Initialization and Connection
|
|
47
|
+
|
|
48
|
+
### Environment Variables
|
|
49
|
+
|
|
50
|
+
Configure RabbitMQ connection using environment variables:
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
// .env file
|
|
54
|
+
RABBITMQ_URL=amqp://username:password@localhost:5672
|
|
55
|
+
RABBITMQ_HOST=localhost
|
|
56
|
+
RABBITMQ_PORT=5672
|
|
57
|
+
RABBITMQ_USER=guest
|
|
58
|
+
RABBITMQ_PASS=guest
|
|
59
|
+
RABBITMQ_VHOST=/
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Basic Connection (Promise API)
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
const amqp = require('amqplib');
|
|
66
|
+
|
|
67
|
+
async function connect() {
|
|
68
|
+
try {
|
|
69
|
+
// Using connection URL from environment
|
|
70
|
+
const connection = await amqp.connect(process.env.RABBITMQ_URL || 'amqp://localhost');
|
|
71
|
+
|
|
72
|
+
console.log('Connected to RabbitMQ');
|
|
73
|
+
return connection;
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error('Connection failed:', error);
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Connection with Options
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
const amqp = require('amqplib');
|
|
85
|
+
|
|
86
|
+
async function connectWithOptions() {
|
|
87
|
+
const connection = await amqp.connect({
|
|
88
|
+
protocol: 'amqp',
|
|
89
|
+
hostname: process.env.RABBITMQ_HOST || 'localhost',
|
|
90
|
+
port: parseInt(process.env.RABBITMQ_PORT) || 5672,
|
|
91
|
+
username: process.env.RABBITMQ_USER || 'guest',
|
|
92
|
+
password: process.env.RABBITMQ_PASS || 'guest',
|
|
93
|
+
vhost: process.env.RABBITMQ_VHOST || '/',
|
|
94
|
+
heartbeat: 30, // Heartbeat interval in seconds (recommended: 30)
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
return connection;
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Connection with Socket Options
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
const amqp = require('amqplib');
|
|
105
|
+
|
|
106
|
+
async function connectWithSocketOptions() {
|
|
107
|
+
const connection = await amqp.connect(
|
|
108
|
+
process.env.RABBITMQ_URL || 'amqp://localhost',
|
|
109
|
+
{
|
|
110
|
+
timeout: 10000, // Socket timeout in milliseconds
|
|
111
|
+
noDelay: true, // Disable Nagle's algorithm
|
|
112
|
+
keepAlive: true, // Enable TCP keep-alive
|
|
113
|
+
keepAliveDelay: 30000 // Keep-alive delay in ms
|
|
114
|
+
}
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
return connection;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Callback API Connection
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
const amqp = require('amqplib/callback_api');
|
|
125
|
+
|
|
126
|
+
amqp.connect('amqp://localhost', function(error, connection) {
|
|
127
|
+
if (error) {
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
console.log('Connected to RabbitMQ');
|
|
131
|
+
|
|
132
|
+
// Use connection here
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Channel API
|
|
137
|
+
|
|
138
|
+
### Creating a Channel
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
const amqp = require('amqplib');
|
|
142
|
+
|
|
143
|
+
async function createChannel() {
|
|
144
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
145
|
+
const channel = await connection.createChannel();
|
|
146
|
+
|
|
147
|
+
return { connection, channel };
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Creating a Confirm Channel
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
const amqp = require('amqplib');
|
|
155
|
+
|
|
156
|
+
async function createConfirmChannel() {
|
|
157
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
158
|
+
const channel = await connection.createConfirmChannel();
|
|
159
|
+
|
|
160
|
+
// Confirm channel provides publisher confirms
|
|
161
|
+
return { connection, channel };
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Core Messaging Patterns
|
|
166
|
+
|
|
167
|
+
### 1. Simple Queue - Producer
|
|
168
|
+
|
|
169
|
+
```javascript
|
|
170
|
+
const amqp = require('amqplib');
|
|
171
|
+
|
|
172
|
+
async function sendMessage(queueName, message) {
|
|
173
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
174
|
+
const channel = await connection.createChannel();
|
|
175
|
+
|
|
176
|
+
// Assert queue exists (create if it doesn't)
|
|
177
|
+
await channel.assertQueue(queueName, {
|
|
178
|
+
durable: true // Queue survives broker restart
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Send message
|
|
182
|
+
channel.sendToQueue(queueName, Buffer.from(message), {
|
|
183
|
+
persistent: true // Message survives broker restart
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
console.log(`Sent: ${message}`);
|
|
187
|
+
|
|
188
|
+
// Close connection after a delay to ensure message is sent
|
|
189
|
+
setTimeout(() => {
|
|
190
|
+
connection.close();
|
|
191
|
+
}, 500);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Usage
|
|
195
|
+
sendMessage('task_queue', 'Hello World!');
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 2. Simple Queue - Consumer
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
const amqp = require('amqplib');
|
|
202
|
+
|
|
203
|
+
async function receiveMessages(queueName) {
|
|
204
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
205
|
+
const channel = await connection.createChannel();
|
|
206
|
+
|
|
207
|
+
await channel.assertQueue(queueName, {
|
|
208
|
+
durable: true
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
console.log(`Waiting for messages in ${queueName}`);
|
|
212
|
+
|
|
213
|
+
// Consume messages
|
|
214
|
+
channel.consume(queueName, (msg) => {
|
|
215
|
+
if (msg !== null) {
|
|
216
|
+
const content = msg.content.toString();
|
|
217
|
+
console.log(`Received: ${content}`);
|
|
218
|
+
|
|
219
|
+
// Acknowledge message
|
|
220
|
+
channel.ack(msg);
|
|
221
|
+
}
|
|
222
|
+
}, {
|
|
223
|
+
noAck: false // Manual acknowledgment
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Usage
|
|
228
|
+
receiveMessages('task_queue');
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### 3. Work Queue with Prefetch
|
|
232
|
+
|
|
233
|
+
```javascript
|
|
234
|
+
const amqp = require('amqplib');
|
|
235
|
+
|
|
236
|
+
async function worker(queueName) {
|
|
237
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
238
|
+
const channel = await connection.createChannel();
|
|
239
|
+
|
|
240
|
+
await channel.assertQueue(queueName, {
|
|
241
|
+
durable: true
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Fair dispatch - only send one message at a time to each worker
|
|
245
|
+
channel.prefetch(1);
|
|
246
|
+
|
|
247
|
+
console.log(`Worker waiting for tasks in ${queueName}`);
|
|
248
|
+
|
|
249
|
+
channel.consume(queueName, async (msg) => {
|
|
250
|
+
if (msg !== null) {
|
|
251
|
+
const task = msg.content.toString();
|
|
252
|
+
console.log(`Processing: ${task}`);
|
|
253
|
+
|
|
254
|
+
// Simulate work
|
|
255
|
+
const workTime = (task.match(/\./g) || []).length * 1000;
|
|
256
|
+
await new Promise(resolve => setTimeout(resolve, workTime));
|
|
257
|
+
|
|
258
|
+
console.log(`Done: ${task}`);
|
|
259
|
+
channel.ack(msg);
|
|
260
|
+
}
|
|
261
|
+
}, {
|
|
262
|
+
noAck: false
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Usage
|
|
267
|
+
worker('task_queue');
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### 4. Publish/Subscribe with Fanout Exchange
|
|
271
|
+
|
|
272
|
+
**Publisher:**
|
|
273
|
+
|
|
274
|
+
```javascript
|
|
275
|
+
const amqp = require('amqplib');
|
|
276
|
+
|
|
277
|
+
async function publishLog(message) {
|
|
278
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
279
|
+
const channel = await connection.createChannel();
|
|
280
|
+
|
|
281
|
+
const exchange = 'logs';
|
|
282
|
+
|
|
283
|
+
await channel.assertExchange(exchange, 'fanout', {
|
|
284
|
+
durable: false
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
channel.publish(exchange, '', Buffer.from(message));
|
|
288
|
+
console.log(`Sent: ${message}`);
|
|
289
|
+
|
|
290
|
+
setTimeout(() => {
|
|
291
|
+
connection.close();
|
|
292
|
+
}, 500);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Usage
|
|
296
|
+
publishLog('Hello World!');
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Subscriber:**
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
const amqp = require('amqplib');
|
|
303
|
+
|
|
304
|
+
async function subscribeLogs() {
|
|
305
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
306
|
+
const channel = await connection.createChannel();
|
|
307
|
+
|
|
308
|
+
const exchange = 'logs';
|
|
309
|
+
|
|
310
|
+
await channel.assertExchange(exchange, 'fanout', {
|
|
311
|
+
durable: false
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// Create exclusive queue (auto-delete when consumer disconnects)
|
|
315
|
+
const q = await channel.assertQueue('', {
|
|
316
|
+
exclusive: true
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
console.log(`Waiting for logs. Queue: ${q.queue}`);
|
|
320
|
+
|
|
321
|
+
// Bind queue to exchange
|
|
322
|
+
channel.bindQueue(q.queue, exchange, '');
|
|
323
|
+
|
|
324
|
+
channel.consume(q.queue, (msg) => {
|
|
325
|
+
if (msg !== null) {
|
|
326
|
+
console.log(`Received: ${msg.content.toString()}`);
|
|
327
|
+
}
|
|
328
|
+
}, {
|
|
329
|
+
noAck: true
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Usage
|
|
334
|
+
subscribeLogs();
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### 5. Routing with Direct Exchange
|
|
338
|
+
|
|
339
|
+
**Emitter:**
|
|
340
|
+
|
|
341
|
+
```javascript
|
|
342
|
+
const amqp = require('amqplib');
|
|
343
|
+
|
|
344
|
+
async function emitLog(severity, message) {
|
|
345
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
346
|
+
const channel = await connection.createChannel();
|
|
347
|
+
|
|
348
|
+
const exchange = 'direct_logs';
|
|
349
|
+
|
|
350
|
+
await channel.assertExchange(exchange, 'direct', {
|
|
351
|
+
durable: false
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
channel.publish(exchange, severity, Buffer.from(message));
|
|
355
|
+
console.log(`Sent [${severity}]: ${message}`);
|
|
356
|
+
|
|
357
|
+
setTimeout(() => {
|
|
358
|
+
connection.close();
|
|
359
|
+
}, 500);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Usage
|
|
363
|
+
emitLog('error', 'Critical system error!');
|
|
364
|
+
emitLog('info', 'System started');
|
|
365
|
+
emitLog('warning', 'Disk space low');
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**Receiver:**
|
|
369
|
+
|
|
370
|
+
```javascript
|
|
371
|
+
const amqp = require('amqplib');
|
|
372
|
+
|
|
373
|
+
async function receiveLogs(severities) {
|
|
374
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
375
|
+
const channel = await connection.createChannel();
|
|
376
|
+
|
|
377
|
+
const exchange = 'direct_logs';
|
|
378
|
+
|
|
379
|
+
await channel.assertExchange(exchange, 'direct', {
|
|
380
|
+
durable: false
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
const q = await channel.assertQueue('', {
|
|
384
|
+
exclusive: true
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
console.log(`Waiting for logs with severities: ${severities.join(', ')}`);
|
|
388
|
+
|
|
389
|
+
// Bind queue for each severity
|
|
390
|
+
for (const severity of severities) {
|
|
391
|
+
channel.bindQueue(q.queue, exchange, severity);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
channel.consume(q.queue, (msg) => {
|
|
395
|
+
if (msg !== null) {
|
|
396
|
+
console.log(`[${msg.fields.routingKey}]: ${msg.content.toString()}`);
|
|
397
|
+
}
|
|
398
|
+
}, {
|
|
399
|
+
noAck: true
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Usage - receive only error and warning logs
|
|
404
|
+
receiveLogs(['error', 'warning']);
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### 6. Topics with Topic Exchange
|
|
408
|
+
|
|
409
|
+
**Emit Log Topic:**
|
|
410
|
+
|
|
411
|
+
```javascript
|
|
412
|
+
const amqp = require('amqplib');
|
|
413
|
+
|
|
414
|
+
async function emitLogTopic(routingKey, message) {
|
|
415
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
416
|
+
const channel = await connection.createChannel();
|
|
417
|
+
|
|
418
|
+
const exchange = 'topic_logs';
|
|
419
|
+
|
|
420
|
+
await channel.assertExchange(exchange, 'topic', {
|
|
421
|
+
durable: false
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
channel.publish(exchange, routingKey, Buffer.from(message));
|
|
425
|
+
console.log(`Sent [${routingKey}]: ${message}`);
|
|
426
|
+
|
|
427
|
+
setTimeout(() => {
|
|
428
|
+
connection.close();
|
|
429
|
+
}, 500);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Usage - routing keys with dot-separated words
|
|
433
|
+
emitLogTopic('kern.critical', 'A critical kernel error');
|
|
434
|
+
emitLogTopic('kern.info', 'Kernel information');
|
|
435
|
+
emitLogTopic('auth.warning', 'Authentication warning');
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
**Receive Log Topic:**
|
|
439
|
+
|
|
440
|
+
```javascript
|
|
441
|
+
const amqp = require('amqplib');
|
|
442
|
+
|
|
443
|
+
async function receiveLogsTopic(bindingKeys) {
|
|
444
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
445
|
+
const channel = await connection.createChannel();
|
|
446
|
+
|
|
447
|
+
const exchange = 'topic_logs';
|
|
448
|
+
|
|
449
|
+
await channel.assertExchange(exchange, 'topic', {
|
|
450
|
+
durable: false
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
const q = await channel.assertQueue('', {
|
|
454
|
+
exclusive: true
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
console.log(`Waiting for logs matching: ${bindingKeys.join(', ')}`);
|
|
458
|
+
|
|
459
|
+
// Bind queue with patterns
|
|
460
|
+
// * (star) can substitute for exactly one word
|
|
461
|
+
// # (hash) can substitute for zero or more words
|
|
462
|
+
for (const key of bindingKeys) {
|
|
463
|
+
channel.bindQueue(q.queue, exchange, key);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
channel.consume(q.queue, (msg) => {
|
|
467
|
+
if (msg !== null) {
|
|
468
|
+
console.log(`[${msg.fields.routingKey}]: ${msg.content.toString()}`);
|
|
469
|
+
}
|
|
470
|
+
}, {
|
|
471
|
+
noAck: true
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Usage - pattern matching
|
|
476
|
+
receiveLogsTopic(['kern.*']); // All kernel messages
|
|
477
|
+
receiveLogsTopic(['*.critical']); // All critical messages
|
|
478
|
+
receiveLogsTopic(['kern.#']); // All kern.* messages
|
|
479
|
+
receiveLogsTopic(['#']); // All messages
|
|
480
|
+
receiveLogsTopic(['kern.critical', 'auth.*']); // Multiple patterns
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### 7. RPC (Remote Procedure Call) Pattern
|
|
484
|
+
|
|
485
|
+
**RPC Client:**
|
|
486
|
+
|
|
487
|
+
```javascript
|
|
488
|
+
const amqp = require('amqplib');
|
|
489
|
+
const { v4: uuidv4 } = require('uuid');
|
|
490
|
+
|
|
491
|
+
class RPCClient {
|
|
492
|
+
constructor() {
|
|
493
|
+
this.connection = null;
|
|
494
|
+
this.channel = null;
|
|
495
|
+
this.replyQueue = null;
|
|
496
|
+
this.responseHandlers = new Map();
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
async connect() {
|
|
500
|
+
this.connection = await amqp.connect('amqp://localhost');
|
|
501
|
+
this.channel = await this.connection.createChannel();
|
|
502
|
+
|
|
503
|
+
// Create reply queue
|
|
504
|
+
const q = await this.channel.assertQueue('', {
|
|
505
|
+
exclusive: true
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
this.replyQueue = q.queue;
|
|
509
|
+
|
|
510
|
+
// Consume from reply queue
|
|
511
|
+
this.channel.consume(this.replyQueue, (msg) => {
|
|
512
|
+
const correlationId = msg.properties.correlationId;
|
|
513
|
+
const handler = this.responseHandlers.get(correlationId);
|
|
514
|
+
|
|
515
|
+
if (handler) {
|
|
516
|
+
handler(msg.content.toString());
|
|
517
|
+
this.responseHandlers.delete(correlationId);
|
|
518
|
+
}
|
|
519
|
+
}, {
|
|
520
|
+
noAck: true
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
async call(n) {
|
|
525
|
+
const correlationId = uuidv4();
|
|
526
|
+
|
|
527
|
+
return new Promise((resolve) => {
|
|
528
|
+
// Store response handler
|
|
529
|
+
this.responseHandlers.set(correlationId, resolve);
|
|
530
|
+
|
|
531
|
+
// Send RPC request
|
|
532
|
+
this.channel.sendToQueue('rpc_queue', Buffer.from(n.toString()), {
|
|
533
|
+
correlationId: correlationId,
|
|
534
|
+
replyTo: this.replyQueue
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
async close() {
|
|
540
|
+
await this.connection.close();
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Usage
|
|
545
|
+
async function makeRPCCall() {
|
|
546
|
+
const client = new RPCClient();
|
|
547
|
+
await client.connect();
|
|
548
|
+
|
|
549
|
+
console.log('Requesting fib(30)');
|
|
550
|
+
const result = await client.call(30);
|
|
551
|
+
console.log(`Result: ${result}`);
|
|
552
|
+
|
|
553
|
+
await client.close();
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
makeRPCCall();
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
**RPC Server:**
|
|
560
|
+
|
|
561
|
+
```javascript
|
|
562
|
+
const amqp = require('amqplib');
|
|
563
|
+
|
|
564
|
+
function fibonacci(n) {
|
|
565
|
+
if (n === 0 || n === 1) return n;
|
|
566
|
+
return fibonacci(n - 1) + fibonacci(n - 2);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
async function startRPCServer() {
|
|
570
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
571
|
+
const channel = await connection.createChannel();
|
|
572
|
+
|
|
573
|
+
const queue = 'rpc_queue';
|
|
574
|
+
|
|
575
|
+
await channel.assertQueue(queue, {
|
|
576
|
+
durable: false
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
channel.prefetch(1);
|
|
580
|
+
console.log('Awaiting RPC requests');
|
|
581
|
+
|
|
582
|
+
channel.consume(queue, (msg) => {
|
|
583
|
+
const n = parseInt(msg.content.toString());
|
|
584
|
+
|
|
585
|
+
console.log(`Computing fibonacci(${n})`);
|
|
586
|
+
const result = fibonacci(n);
|
|
587
|
+
|
|
588
|
+
// Send response
|
|
589
|
+
channel.sendToQueue(
|
|
590
|
+
msg.properties.replyTo,
|
|
591
|
+
Buffer.from(result.toString()),
|
|
592
|
+
{
|
|
593
|
+
correlationId: msg.properties.correlationId
|
|
594
|
+
}
|
|
595
|
+
);
|
|
596
|
+
|
|
597
|
+
channel.ack(msg);
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
startRPCServer();
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
## Advanced Configuration
|
|
605
|
+
|
|
606
|
+
### Message Properties
|
|
607
|
+
|
|
608
|
+
```javascript
|
|
609
|
+
const amqp = require('amqplib');
|
|
610
|
+
|
|
611
|
+
async function sendWithProperties(queue, message) {
|
|
612
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
613
|
+
const channel = await connection.createChannel();
|
|
614
|
+
|
|
615
|
+
await channel.assertQueue(queue, { durable: true });
|
|
616
|
+
|
|
617
|
+
channel.sendToQueue(queue, Buffer.from(message), {
|
|
618
|
+
persistent: true, // Survive broker restart
|
|
619
|
+
expiration: '60000', // Message TTL in milliseconds
|
|
620
|
+
priority: 5, // Message priority (0-255)
|
|
621
|
+
contentType: 'application/json', // MIME type
|
|
622
|
+
contentEncoding: 'utf-8', // Encoding
|
|
623
|
+
timestamp: Date.now(), // Timestamp
|
|
624
|
+
messageId: 'msg-123', // Application message ID
|
|
625
|
+
userId: 'guest', // Creating user
|
|
626
|
+
appId: 'my-app', // Application ID
|
|
627
|
+
headers: { // Custom headers
|
|
628
|
+
'x-custom-header': 'value'
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
setTimeout(() => connection.close(), 500);
|
|
633
|
+
}
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### Queue Options
|
|
637
|
+
|
|
638
|
+
```javascript
|
|
639
|
+
const amqp = require('amqplib');
|
|
640
|
+
|
|
641
|
+
async function declareQueueWithOptions() {
|
|
642
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
643
|
+
const channel = await connection.createChannel();
|
|
644
|
+
|
|
645
|
+
await channel.assertQueue('advanced_queue', {
|
|
646
|
+
durable: true, // Queue survives broker restart
|
|
647
|
+
exclusive: false, // Can be accessed by other connections
|
|
648
|
+
autoDelete: false, // Queue won't be deleted when no consumers
|
|
649
|
+
messageTtl: 60000, // Message TTL in milliseconds
|
|
650
|
+
expires: 300000, // Queue expires after 5 minutes of non-use
|
|
651
|
+
maxLength: 1000, // Maximum queue length
|
|
652
|
+
maxPriority: 10, // Enable priority queue (0-10)
|
|
653
|
+
deadLetterExchange: 'dlx', // DLX for rejected messages
|
|
654
|
+
deadLetterRoutingKey: 'dead.letter' // Routing key for DLX
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
await connection.close();
|
|
658
|
+
}
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
### Exchange Options
|
|
662
|
+
|
|
663
|
+
```javascript
|
|
664
|
+
const amqp = require('amqplib');
|
|
665
|
+
|
|
666
|
+
async function declareExchangeWithOptions() {
|
|
667
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
668
|
+
const channel = await connection.createChannel();
|
|
669
|
+
|
|
670
|
+
await channel.assertExchange('advanced_exchange', 'topic', {
|
|
671
|
+
durable: true, // Exchange survives broker restart
|
|
672
|
+
autoDelete: false, // Exchange won't be deleted when no bindings
|
|
673
|
+
internal: false, // Can be published to by clients
|
|
674
|
+
alternateExchange: 'alternate_exchange' // AE for unroutable messages
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
await connection.close();
|
|
678
|
+
}
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### Dead Letter Queue (DLQ)
|
|
682
|
+
|
|
683
|
+
```javascript
|
|
684
|
+
const amqp = require('amqplib');
|
|
685
|
+
|
|
686
|
+
async function setupDeadLetterQueue() {
|
|
687
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
688
|
+
const channel = await connection.createChannel();
|
|
689
|
+
|
|
690
|
+
// Declare dead letter exchange
|
|
691
|
+
await channel.assertExchange('dlx', 'direct', {
|
|
692
|
+
durable: true
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
// Declare dead letter queue
|
|
696
|
+
await channel.assertQueue('dead_letter_queue', {
|
|
697
|
+
durable: true
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
// Bind DLQ to DLX
|
|
701
|
+
await channel.bindQueue('dead_letter_queue', 'dlx', 'dead.letter');
|
|
702
|
+
|
|
703
|
+
// Declare main queue with DLX
|
|
704
|
+
await channel.assertQueue('main_queue', {
|
|
705
|
+
durable: true,
|
|
706
|
+
deadLetterExchange: 'dlx',
|
|
707
|
+
deadLetterRoutingKey: 'dead.letter',
|
|
708
|
+
messageTtl: 10000 // Messages expire after 10 seconds
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
console.log('Dead letter queue setup complete');
|
|
712
|
+
await connection.close();
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
setupDeadLetterQueue();
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
### Consuming from Dead Letter Queue
|
|
719
|
+
|
|
720
|
+
```javascript
|
|
721
|
+
const amqp = require('amqplib');
|
|
722
|
+
|
|
723
|
+
async function consumeDeadLetters() {
|
|
724
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
725
|
+
const channel = await connection.createChannel();
|
|
726
|
+
|
|
727
|
+
await channel.assertQueue('dead_letter_queue', {
|
|
728
|
+
durable: true
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
console.log('Waiting for dead letter messages');
|
|
732
|
+
|
|
733
|
+
channel.consume('dead_letter_queue', (msg) => {
|
|
734
|
+
if (msg !== null) {
|
|
735
|
+
console.log('Dead letter received:', msg.content.toString());
|
|
736
|
+
console.log('Original routing key:', msg.fields.routingKey);
|
|
737
|
+
console.log('Death reason:', msg.properties.headers['x-death']);
|
|
738
|
+
|
|
739
|
+
// Process or log dead letter
|
|
740
|
+
channel.ack(msg);
|
|
741
|
+
}
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
consumeDeadLetters();
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
### Message Rejection and Requeuing
|
|
749
|
+
|
|
750
|
+
```javascript
|
|
751
|
+
const amqp = require('amqplib');
|
|
752
|
+
|
|
753
|
+
async function consumerWithRetry() {
|
|
754
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
755
|
+
const channel = await connection.createChannel();
|
|
756
|
+
|
|
757
|
+
await channel.assertQueue('task_queue', {
|
|
758
|
+
durable: true
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
channel.consume('task_queue', async (msg) => {
|
|
762
|
+
if (msg !== null) {
|
|
763
|
+
try {
|
|
764
|
+
const task = msg.content.toString();
|
|
765
|
+
console.log('Processing:', task);
|
|
766
|
+
|
|
767
|
+
// Simulate processing
|
|
768
|
+
await processTask(task);
|
|
769
|
+
|
|
770
|
+
// Success - acknowledge
|
|
771
|
+
channel.ack(msg);
|
|
772
|
+
} catch (error) {
|
|
773
|
+
console.error('Processing failed:', error);
|
|
774
|
+
|
|
775
|
+
// Check retry count
|
|
776
|
+
const retryCount = (msg.properties.headers?.['x-retry-count'] || 0);
|
|
777
|
+
|
|
778
|
+
if (retryCount < 3) {
|
|
779
|
+
// Reject and requeue for retry
|
|
780
|
+
channel.nack(msg, false, true);
|
|
781
|
+
} else {
|
|
782
|
+
// Max retries reached - reject without requeue (goes to DLQ)
|
|
783
|
+
channel.nack(msg, false, false);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
async function processTask(task) {
|
|
791
|
+
// Simulate work
|
|
792
|
+
if (Math.random() < 0.3) {
|
|
793
|
+
throw new Error('Random failure');
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
consumerWithRetry();
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
### Publisher Confirms
|
|
801
|
+
|
|
802
|
+
```javascript
|
|
803
|
+
const amqp = require('amqplib');
|
|
804
|
+
|
|
805
|
+
async function publishWithConfirm() {
|
|
806
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
807
|
+
const channel = await connection.createConfirmChannel();
|
|
808
|
+
|
|
809
|
+
const queue = 'confirm_queue';
|
|
810
|
+
await channel.assertQueue(queue, { durable: true });
|
|
811
|
+
|
|
812
|
+
const message = 'Important message';
|
|
813
|
+
|
|
814
|
+
try {
|
|
815
|
+
channel.sendToQueue(queue, Buffer.from(message), {
|
|
816
|
+
persistent: true
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
// Wait for confirmation
|
|
820
|
+
await channel.waitForConfirms();
|
|
821
|
+
console.log('Message confirmed by broker');
|
|
822
|
+
} catch (error) {
|
|
823
|
+
console.error('Message nacked by broker:', error);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
await connection.close();
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
publishWithConfirm();
|
|
830
|
+
```
|
|
831
|
+
|
|
832
|
+
### Batch Publishing with Confirms
|
|
833
|
+
|
|
834
|
+
```javascript
|
|
835
|
+
const amqp = require('amqplib');
|
|
836
|
+
|
|
837
|
+
async function batchPublishWithConfirms() {
|
|
838
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
839
|
+
const channel = await connection.createConfirmChannel();
|
|
840
|
+
|
|
841
|
+
const queue = 'batch_queue';
|
|
842
|
+
await channel.assertQueue(queue, { durable: true });
|
|
843
|
+
|
|
844
|
+
const messages = Array.from({ length: 100 }, (_, i) => `Message ${i}`);
|
|
845
|
+
|
|
846
|
+
for (const message of messages) {
|
|
847
|
+
channel.sendToQueue(queue, Buffer.from(message), {
|
|
848
|
+
persistent: true
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
try {
|
|
853
|
+
await channel.waitForConfirms();
|
|
854
|
+
console.log('All messages confirmed');
|
|
855
|
+
} catch (error) {
|
|
856
|
+
console.error('Some messages were nacked:', error);
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
await connection.close();
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
batchPublishWithConfirms();
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
## Error Handling and Reconnection
|
|
866
|
+
|
|
867
|
+
### Connection Error Handling
|
|
868
|
+
|
|
869
|
+
```javascript
|
|
870
|
+
const amqp = require('amqplib');
|
|
871
|
+
|
|
872
|
+
async function connectWithErrorHandling() {
|
|
873
|
+
let connection;
|
|
874
|
+
|
|
875
|
+
try {
|
|
876
|
+
connection = await amqp.connect('amqp://localhost');
|
|
877
|
+
|
|
878
|
+
// Handle connection errors
|
|
879
|
+
connection.on('error', (err) => {
|
|
880
|
+
console.error('Connection error:', err);
|
|
881
|
+
});
|
|
882
|
+
|
|
883
|
+
// Handle connection close
|
|
884
|
+
connection.on('close', () => {
|
|
885
|
+
console.log('Connection closed');
|
|
886
|
+
// Implement reconnection logic here
|
|
887
|
+
setTimeout(() => {
|
|
888
|
+
console.log('Attempting to reconnect...');
|
|
889
|
+
connectWithErrorHandling();
|
|
890
|
+
}, 5000);
|
|
891
|
+
});
|
|
892
|
+
|
|
893
|
+
const channel = await connection.createChannel();
|
|
894
|
+
|
|
895
|
+
// Handle channel errors
|
|
896
|
+
channel.on('error', (err) => {
|
|
897
|
+
console.error('Channel error:', err);
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
// Handle channel close
|
|
901
|
+
channel.on('close', () => {
|
|
902
|
+
console.log('Channel closed');
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
return { connection, channel };
|
|
906
|
+
} catch (error) {
|
|
907
|
+
console.error('Failed to connect:', error);
|
|
908
|
+
|
|
909
|
+
// Retry connection after delay
|
|
910
|
+
setTimeout(() => {
|
|
911
|
+
console.log('Retrying connection...');
|
|
912
|
+
connectWithErrorHandling();
|
|
913
|
+
}, 5000);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
connectWithErrorHandling();
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
### Robust Connection Manager
|
|
921
|
+
|
|
922
|
+
```javascript
|
|
923
|
+
const amqp = require('amqplib');
|
|
924
|
+
|
|
925
|
+
class RabbitMQConnection {
|
|
926
|
+
constructor(url) {
|
|
927
|
+
this.url = url;
|
|
928
|
+
this.connection = null;
|
|
929
|
+
this.channel = null;
|
|
930
|
+
this.reconnecting = false;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
async connect() {
|
|
934
|
+
try {
|
|
935
|
+
this.connection = await amqp.connect(this.url);
|
|
936
|
+
this.channel = await this.connection.createChannel();
|
|
937
|
+
|
|
938
|
+
console.log('Connected to RabbitMQ');
|
|
939
|
+
|
|
940
|
+
this.connection.on('error', (err) => {
|
|
941
|
+
console.error('Connection error:', err);
|
|
942
|
+
this.reconnect();
|
|
943
|
+
});
|
|
944
|
+
|
|
945
|
+
this.connection.on('close', () => {
|
|
946
|
+
console.log('Connection closed');
|
|
947
|
+
this.reconnect();
|
|
948
|
+
});
|
|
949
|
+
|
|
950
|
+
return this.channel;
|
|
951
|
+
} catch (error) {
|
|
952
|
+
console.error('Connection failed:', error);
|
|
953
|
+
this.reconnect();
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
async reconnect() {
|
|
958
|
+
if (this.reconnecting) return;
|
|
959
|
+
|
|
960
|
+
this.reconnecting = true;
|
|
961
|
+
console.log('Reconnecting in 5 seconds...');
|
|
962
|
+
|
|
963
|
+
setTimeout(async () => {
|
|
964
|
+
this.reconnecting = false;
|
|
965
|
+
await this.connect();
|
|
966
|
+
}, 5000);
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
async close() {
|
|
970
|
+
if (this.channel) {
|
|
971
|
+
await this.channel.close();
|
|
972
|
+
}
|
|
973
|
+
if (this.connection) {
|
|
974
|
+
await this.connection.close();
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// Usage
|
|
980
|
+
const manager = new RabbitMQConnection('amqp://localhost');
|
|
981
|
+
const channel = await manager.connect();
|
|
982
|
+
```
|
|
983
|
+
|
|
984
|
+
### Graceful Shutdown
|
|
985
|
+
|
|
986
|
+
```javascript
|
|
987
|
+
const amqp = require('amqplib');
|
|
988
|
+
|
|
989
|
+
let connection = null;
|
|
990
|
+
let channel = null;
|
|
991
|
+
|
|
992
|
+
async function setup() {
|
|
993
|
+
connection = await amqp.connect('amqp://localhost');
|
|
994
|
+
channel = await connection.createChannel();
|
|
995
|
+
|
|
996
|
+
await channel.assertQueue('shutdown_queue', { durable: true });
|
|
997
|
+
|
|
998
|
+
channel.consume('shutdown_queue', (msg) => {
|
|
999
|
+
if (msg !== null) {
|
|
1000
|
+
console.log('Processing:', msg.content.toString());
|
|
1001
|
+
channel.ack(msg);
|
|
1002
|
+
}
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
async function cleanup() {
|
|
1007
|
+
console.log('Shutting down gracefully...');
|
|
1008
|
+
|
|
1009
|
+
if (channel) {
|
|
1010
|
+
// Cancel consumers
|
|
1011
|
+
await channel.close();
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
if (connection) {
|
|
1015
|
+
await connection.close();
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
console.log('Cleanup complete');
|
|
1019
|
+
process.exit(0);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
// Handle shutdown signals
|
|
1023
|
+
process.on('SIGINT', cleanup);
|
|
1024
|
+
process.on('SIGTERM', cleanup);
|
|
1025
|
+
|
|
1026
|
+
setup();
|
|
1027
|
+
```
|
|
1028
|
+
|
|
1029
|
+
## Common Patterns
|
|
1030
|
+
|
|
1031
|
+
### Message Retry with Delay
|
|
1032
|
+
|
|
1033
|
+
```javascript
|
|
1034
|
+
const amqp = require('amqplib');
|
|
1035
|
+
|
|
1036
|
+
async function setupRetryQueue() {
|
|
1037
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
1038
|
+
const channel = await connection.createChannel();
|
|
1039
|
+
|
|
1040
|
+
// Main queue
|
|
1041
|
+
await channel.assertQueue('main_queue', {
|
|
1042
|
+
durable: true,
|
|
1043
|
+
deadLetterExchange: 'retry',
|
|
1044
|
+
deadLetterRoutingKey: 'retry'
|
|
1045
|
+
});
|
|
1046
|
+
|
|
1047
|
+
// Retry exchange
|
|
1048
|
+
await channel.assertExchange('retry', 'direct', {
|
|
1049
|
+
durable: true
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
// Retry queue with delay
|
|
1053
|
+
await channel.assertQueue('retry_queue', {
|
|
1054
|
+
durable: true,
|
|
1055
|
+
messageTtl: 30000, // 30 second delay
|
|
1056
|
+
deadLetterExchange: '',
|
|
1057
|
+
deadLetterRoutingKey: 'main_queue'
|
|
1058
|
+
});
|
|
1059
|
+
|
|
1060
|
+
await channel.bindQueue('retry_queue', 'retry', 'retry');
|
|
1061
|
+
|
|
1062
|
+
console.log('Retry queue setup complete');
|
|
1063
|
+
await connection.close();
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
setupRetryQueue();
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
### Priority Queue
|
|
1070
|
+
|
|
1071
|
+
```javascript
|
|
1072
|
+
const amqp = require('amqplib');
|
|
1073
|
+
|
|
1074
|
+
async function setupPriorityQueue() {
|
|
1075
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
1076
|
+
const channel = await connection.createChannel();
|
|
1077
|
+
|
|
1078
|
+
// Queue with priority support
|
|
1079
|
+
await channel.assertQueue('priority_queue', {
|
|
1080
|
+
durable: true,
|
|
1081
|
+
maxPriority: 10
|
|
1082
|
+
});
|
|
1083
|
+
|
|
1084
|
+
// Send messages with different priorities
|
|
1085
|
+
channel.sendToQueue('priority_queue', Buffer.from('Low priority'), {
|
|
1086
|
+
priority: 1
|
|
1087
|
+
});
|
|
1088
|
+
|
|
1089
|
+
channel.sendToQueue('priority_queue', Buffer.from('High priority'), {
|
|
1090
|
+
priority: 10
|
|
1091
|
+
});
|
|
1092
|
+
|
|
1093
|
+
channel.sendToQueue('priority_queue', Buffer.from('Medium priority'), {
|
|
1094
|
+
priority: 5
|
|
1095
|
+
});
|
|
1096
|
+
|
|
1097
|
+
setTimeout(() => connection.close(), 500);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
setupPriorityQueue();
|
|
1101
|
+
```
|
|
1102
|
+
|
|
1103
|
+
### Rate Limiting Consumer
|
|
1104
|
+
|
|
1105
|
+
```javascript
|
|
1106
|
+
const amqp = require('amqplib');
|
|
1107
|
+
|
|
1108
|
+
async function rateLimitedConsumer() {
|
|
1109
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
1110
|
+
const channel = await connection.createChannel();
|
|
1111
|
+
|
|
1112
|
+
await channel.assertQueue('rate_limited_queue', {
|
|
1113
|
+
durable: true
|
|
1114
|
+
});
|
|
1115
|
+
|
|
1116
|
+
// Process only 1 message at a time
|
|
1117
|
+
channel.prefetch(1);
|
|
1118
|
+
|
|
1119
|
+
let processing = false;
|
|
1120
|
+
|
|
1121
|
+
channel.consume('rate_limited_queue', async (msg) => {
|
|
1122
|
+
if (msg !== null && !processing) {
|
|
1123
|
+
processing = true;
|
|
1124
|
+
|
|
1125
|
+
console.log('Processing:', msg.content.toString());
|
|
1126
|
+
|
|
1127
|
+
// Simulate rate-limited processing
|
|
1128
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
1129
|
+
|
|
1130
|
+
channel.ack(msg);
|
|
1131
|
+
processing = false;
|
|
1132
|
+
}
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
rateLimitedConsumer();
|
|
1137
|
+
```
|
|
1138
|
+
|
|
1139
|
+
### JSON Message Handling
|
|
1140
|
+
|
|
1141
|
+
```javascript
|
|
1142
|
+
const amqp = require('amqplib');
|
|
1143
|
+
|
|
1144
|
+
async function sendJSON(queue, data) {
|
|
1145
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
1146
|
+
const channel = await connection.createChannel();
|
|
1147
|
+
|
|
1148
|
+
await channel.assertQueue(queue, { durable: true });
|
|
1149
|
+
|
|
1150
|
+
const message = JSON.stringify(data);
|
|
1151
|
+
|
|
1152
|
+
channel.sendToQueue(queue, Buffer.from(message), {
|
|
1153
|
+
contentType: 'application/json',
|
|
1154
|
+
persistent: true
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1157
|
+
console.log('Sent JSON:', data);
|
|
1158
|
+
|
|
1159
|
+
setTimeout(() => connection.close(), 500);
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
async function receiveJSON(queue) {
|
|
1163
|
+
const connection = await amqp.connect('amqp://localhost');
|
|
1164
|
+
const channel = await connection.createChannel();
|
|
1165
|
+
|
|
1166
|
+
await channel.assertQueue(queue, { durable: true });
|
|
1167
|
+
|
|
1168
|
+
channel.consume(queue, (msg) => {
|
|
1169
|
+
if (msg !== null) {
|
|
1170
|
+
try {
|
|
1171
|
+
const data = JSON.parse(msg.content.toString());
|
|
1172
|
+
console.log('Received JSON:', data);
|
|
1173
|
+
channel.ack(msg);
|
|
1174
|
+
} catch (error) {
|
|
1175
|
+
console.error('Invalid JSON:', error);
|
|
1176
|
+
channel.nack(msg, false, false);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// Usage
|
|
1183
|
+
sendJSON('json_queue', { user: 'john', action: 'login', timestamp: Date.now() });
|
|
1184
|
+
receiveJSON('json_queue');
|
|
1185
|
+
```
|
|
1186
|
+
|
|
1187
|
+
## Useful Links
|
|
1188
|
+
|
|
1189
|
+
- **Official Documentation:** https://www.rabbitmq.com/docs
|
|
1190
|
+
- **amqplib GitHub:** https://github.com/amqp-node/amqplib
|
|
1191
|
+
- **amqplib API Reference:** https://amqp-node.github.io/amqplib/channel_api.html
|
|
1192
|
+
- **RabbitMQ Tutorials:** https://www.rabbitmq.com/tutorials
|
|
1193
|
+
- **AMQP 0-9-1 Reference:** https://www.rabbitmq.com/amqp-0-9-1-reference.html
|