├── .husky └── pre-commit ├── dist ├── lib │ ├── type.js.map │ ├── type.js │ ├── type.d.ts │ ├── index.d.ts │ ├── index.js.map │ ├── RabbitMQConnection.d.ts │ ├── Publisher.js.map │ ├── Publisher.d.ts │ ├── Publisher.js │ ├── Consumer.d.ts │ ├── RabbitMQConnection.js.map │ ├── index.js │ ├── RabbitMQClient.d.ts │ ├── RabbitMQConnection.js │ ├── Consumer.js.map │ ├── Consumer.js │ ├── RabbitMQClient.js.map │ └── RabbitMQClient.js ├── tsconfig.eslint.json ├── tsconfig.json └── package.json ├── lib ├── type.ts ├── index.ts ├── Publisher.ts ├── RabbitMQConnection.ts ├── Consumer.ts └── RabbitMQClient.ts ├── tsconfig.eslint.json ├── .gitignore ├── Dockerfile ├── tsconfig.json ├── package.json ├── .eslintrc.js └── README.md /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npm run lint:fix 5 | -------------------------------------------------------------------------------- /dist/lib/type.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"type.js","sourceRoot":"","sources":["../../lib/type.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /dist/lib/type.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | //# sourceMappingURL=type.js.map -------------------------------------------------------------------------------- /lib/type.ts: -------------------------------------------------------------------------------- 1 | export type ConsumerOptions = { 2 | retry: boolean; 3 | retry_count: number; 4 | retry_delay: number; 5 | }; 6 | -------------------------------------------------------------------------------- /dist/lib/type.d.ts: -------------------------------------------------------------------------------- 1 | export type ConsumerOptions = { 2 | retry: boolean; 3 | retry_count: number; 4 | retry_delay: number; 5 | }; 6 | -------------------------------------------------------------------------------- /tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["lib/**/*.ts", "lib/**/*.d.ts", "__tests/**/*.spec.ts", "swc.config.ts", "__tests__/**/*.int.test.ts", ".eslintrc.js"], 4 | } 5 | -------------------------------------------------------------------------------- /dist/tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["lib/**/*.ts", "lib/**/*.d.ts", "__tests/**/*.spec.ts", "swc.config.ts", "__tests__/**/*.int.test.ts", ".eslintrc.js"] 4 | } 5 | -------------------------------------------------------------------------------- /lib/index.ts: -------------------------------------------------------------------------------- 1 | export { RabbitMQConnection } from "./RabbitMQConnection"; 2 | export { RabbitMQClient } from "./RabbitMQClient"; 3 | export { Consumer } from "./Consumer"; 4 | export { Publisher } from "./Publisher"; 5 | -------------------------------------------------------------------------------- /dist/lib/index.d.ts: -------------------------------------------------------------------------------- 1 | export { RabbitMQConnection } from "./RabbitMQConnection"; 2 | export { RabbitMQClient } from "./RabbitMQClient"; 3 | export { Consumer } from "./Consumer"; 4 | export { Publisher } from "./Publisher"; 5 | -------------------------------------------------------------------------------- /dist/lib/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":";;;AAAA,2DAA0D;AAAjD,wHAAA,kBAAkB,OAAA;AAC3B,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,uCAAsC;AAA7B,oGAAA,QAAQ,OAAA;AACjB,yCAAwC;AAA/B,sGAAA,SAAS,OAAA"} -------------------------------------------------------------------------------- /dist/lib/RabbitMQConnection.d.ts: -------------------------------------------------------------------------------- 1 | import { RabbitMQClient } from "./RabbitMQClient"; 2 | export declare class RabbitMQConnection { 3 | private static rabbitMQClient; 4 | static getClient(): RabbitMQClient; 5 | static connect(rabbitMQUrl: string): void; 6 | static close(): void; 7 | } 8 | -------------------------------------------------------------------------------- /dist/lib/Publisher.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"Publisher.js","sourceRoot":"","sources":["../../lib/Publisher.ts"],"names":[],"mappings":";;;AACA,6DAA0D;AAE1D,MAAsB,SAAS;IAO7B,YAAY,SAAiB,EAAE,OAAO,GAAG,EAAE;QACzC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,cAAc,GAAG,uCAAkB,CAAC,SAAS,EAAE,CAAC;QACrD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CAGF;AAdD,8BAcC"} -------------------------------------------------------------------------------- /dist/lib/Publisher.d.ts: -------------------------------------------------------------------------------- 1 | import { RabbitMQClient } from "./RabbitMQClient"; 2 | export declare abstract class Publisher { 3 | protected queueName: string; 4 | protected options: object; 5 | protected rabbitMQClient: RabbitMQClient; 6 | constructor(queueName: string, options?: {}); 7 | abstract publish(message: MessageType): void; 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # dependencies 3 | /node_modules 4 | 5 | #logs 6 | /logs 7 | 8 | #public resources 9 | /public 10 | /tmp 11 | ~/ 12 | # testing 13 | /coverage 14 | 15 | 16 | # misc 17 | .DS_Store 18 | .env.local 19 | .env.development.local 20 | .env.test.local 21 | .env.production.local 22 | .env 23 | package-lock.json 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | yarn.lock 28 | 29 | .idea 30 | 31 | #docker-env 32 | docker-env/aflocal-local.yml 33 | 34 | #build 35 | /build 36 | -------------------------------------------------------------------------------- /dist/lib/Publisher.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.Publisher = void 0; 4 | const RabbitMQConnection_1 = require("./RabbitMQConnection"); 5 | class Publisher { 6 | constructor(queueName, options = {}) { 7 | this.queueName = queueName; 8 | this.rabbitMQClient = RabbitMQConnection_1.RabbitMQConnection.getClient(); 9 | this.options = options; 10 | } 11 | } 12 | exports.Publisher = Publisher; 13 | //# sourceMappingURL=Publisher.js.map -------------------------------------------------------------------------------- /dist/lib/Consumer.d.ts: -------------------------------------------------------------------------------- 1 | import { RabbitMQClient } from "./RabbitMQClient"; 2 | import { ConsumerOptions } from "./type"; 3 | export declare abstract class Consumer { 4 | protected queueName: string; 5 | protected retry: boolean; 6 | protected retryCount: number; 7 | protected retryDelay: number; 8 | protected rabbitMQClient: RabbitMQClient; 9 | constructor(queueName: string, options?: ConsumerOptions); 10 | abstract execute(message: MessageType): void; 11 | consume(): Promise; 12 | } 13 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rabbitmq:3.12.0-management 2 | 3 | RUN apt-get update 4 | 5 | RUN apt-get install -y curl 6 | 7 | RUN curl -L https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases/download/v3.12.0/rabbitmq_delayed_message_exchange-3.12.0.ez > $RABBITMQ_HOME/plugins/rabbitmq_delayed_message_exchange-3.12.0.ez 8 | 9 | RUN chown rabbitmq:rabbitmq $RABBITMQ_HOME/plugins/rabbitmq_delayed_message_exchange-3.12.0.ez 10 | 11 | RUN rabbitmq-plugins enable --offline rabbitmq_delayed_message_exchange 12 | 13 | RUN rabbitmq-plugins enable --offline rabbitmq_consistent_hash_exchange -------------------------------------------------------------------------------- /lib/Publisher.ts: -------------------------------------------------------------------------------- 1 | import { RabbitMQClient } from "./RabbitMQClient"; 2 | import { RabbitMQConnection } from "./RabbitMQConnection"; 3 | 4 | export abstract class Publisher { 5 | protected queueName: string; 6 | 7 | protected options: object; 8 | 9 | protected rabbitMQClient: RabbitMQClient; 10 | 11 | constructor(queueName: string, options = {}) { 12 | this.queueName = queueName; 13 | this.rabbitMQClient = RabbitMQConnection.getClient(); 14 | this.options = options; 15 | } 16 | 17 | abstract publish(message: MessageType): void; 18 | } 19 | -------------------------------------------------------------------------------- /dist/lib/RabbitMQConnection.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"RabbitMQConnection.js","sourceRoot":"","sources":["../../lib/RabbitMQConnection.ts"],"names":[],"mappings":";;;AAAA,qDAAkD;AAElD,MAAa,kBAAkB;IAG7B,MAAM,CAAC,SAAS;QACd,IAAI,CAAC,kBAAkB,CAAC,cAAc,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CACb,4EAA4E,CAC7E,CAAC;QACJ,CAAC;QACD,OAAO,kBAAkB,CAAC,cAAc,CAAC;IAC3C,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,WAAmB;QAChC,IAAI,CAAC,kBAAkB,CAAC,cAAc,EAAE,CAAC;YACvC,kBAAkB,CAAC,cAAc,GAAG,IAAI,+BAAc,CAAC,WAAW,CAAC,CAAC;YACpE,wCAAwC;YACxC,kBAAkB,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;QAC9C,CAAC;IACH,CAAC;IAED,MAAM,CAAC,KAAK;QACV,IAAI,CAAC,kBAAkB,CAAC,cAAc,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CACb,4EAA4E,CAC7E,CAAC;QACJ,CAAC;QACD,kBAAkB,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;IAC5C,CAAC;;AA3BH,gDA4BC;AA3BgB,iCAAc,GAA0B,IAAI,CAAC"} -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": "./", 4 | "outDir": "dist", 5 | "module": "commonjs", 6 | "esModuleInterop": true, 7 | "target": "es6", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "checkJs": true, 11 | "emitDecoratorMetadata": true, 12 | "experimentalDecorators": true, 13 | "sourceMap": true, 14 | "noImplicitAny": false, 15 | "forceConsistentCasingInFileNames": true, 16 | "skipLibCheck": true, 17 | "baseUrl": "./", 18 | "declaration": true, 19 | "typeRoots": ["lib/types", "node_modules/@types/"] 20 | }, 21 | "lib": [ 22 | "es5", 23 | "es6" 24 | ], 25 | "include": [ 26 | "lib/**/*.ts", 27 | "**/*.json" 28 | ], 29 | "exclude": [ 30 | "node_modules", 31 | "dist", 32 | "build", 33 | "coverage" 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /dist/lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.Publisher = exports.Consumer = exports.RabbitMQClient = exports.RabbitMQConnection = void 0; 4 | var RabbitMQConnection_1 = require("./RabbitMQConnection"); 5 | Object.defineProperty(exports, "RabbitMQConnection", { enumerable: true, get: function () { return RabbitMQConnection_1.RabbitMQConnection; } }); 6 | var RabbitMQClient_1 = require("./RabbitMQClient"); 7 | Object.defineProperty(exports, "RabbitMQClient", { enumerable: true, get: function () { return RabbitMQClient_1.RabbitMQClient; } }); 8 | var Consumer_1 = require("./Consumer"); 9 | Object.defineProperty(exports, "Consumer", { enumerable: true, get: function () { return Consumer_1.Consumer; } }); 10 | var Publisher_1 = require("./Publisher"); 11 | Object.defineProperty(exports, "Publisher", { enumerable: true, get: function () { return Publisher_1.Publisher; } }); 12 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": "./", 4 | "outDir": "dist", 5 | "module": "commonjs", 6 | "esModuleInterop": true, 7 | "target": "es6", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "checkJs": true, 11 | "emitDecoratorMetadata": true, 12 | "experimentalDecorators": true, 13 | "sourceMap": true, 14 | "noImplicitAny": false, 15 | "forceConsistentCasingInFileNames": true, 16 | "skipLibCheck": true, 17 | "baseUrl": "./", 18 | "declaration": true, 19 | "typeRoots": ["lib/types", "node_modules/@types/"] 20 | }, 21 | "lib": [ 22 | "es5", 23 | "es6" 24 | ], 25 | "include": [ 26 | "lib/**/*.ts", 27 | "**/*.json" 28 | ], 29 | "exclude": [ 30 | "node_modules", 31 | "dist", 32 | "build", 33 | "coverage" 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /dist/lib/RabbitMQClient.d.ts: -------------------------------------------------------------------------------- 1 | import * as amqp from "amqplib"; 2 | declare type Options = { 3 | exchange?: string; 4 | routingKey?: string; 5 | persistent?: boolean; 6 | delay?: number; 7 | exchangeType?: "direct" | "fanout" | "topic"; 8 | headers?: object; 9 | }; 10 | export declare class RabbitMQClient { 11 | private url; 12 | private static connection; 13 | private channel; 14 | constructor(url: string); 15 | getChannel(): amqp.Channel; 16 | connect(): Promise; 17 | publish(queue: string, message: MessageType, options?: Options): Promise; 18 | sendToQueue(queue: string, message: MessageType, options?: Options): Promise; 19 | consume(queue: string, callback: (message: amqp.ConsumeMessage | null) => void): Promise; 20 | ack(message: amqp.ConsumeMessage | null): Promise; 21 | nack(message: amqp.ConsumeMessage | null): Promise; 22 | getConsumerCount(queue: string): Promise; 23 | close(): Promise; 24 | } 25 | export {}; 26 | -------------------------------------------------------------------------------- /lib/RabbitMQConnection.ts: -------------------------------------------------------------------------------- 1 | import { RabbitMQClient } from "./RabbitMQClient"; 2 | 3 | export class RabbitMQConnection { 4 | private static rabbitMQClient: RabbitMQClient | null = null; 5 | 6 | static getClient(): RabbitMQClient { 7 | if (!RabbitMQConnection.rabbitMQClient) { 8 | throw new Error( 9 | "RabbitMQ client not initialized. Call connect before accessing the client." 10 | ); 11 | } 12 | return RabbitMQConnection.rabbitMQClient; 13 | } 14 | 15 | static connect(rabbitMQUrl: string): void { 16 | if (!RabbitMQConnection.rabbitMQClient) { 17 | RabbitMQConnection.rabbitMQClient = new RabbitMQClient(rabbitMQUrl); 18 | // Additional connection logic if needed 19 | RabbitMQConnection.rabbitMQClient.connect(); 20 | } 21 | } 22 | 23 | static close(): void { 24 | if (!RabbitMQConnection.rabbitMQClient) { 25 | throw new Error( 26 | "RabbitMQ client not initialized. Call connect before accessing the client." 27 | ); 28 | } 29 | RabbitMQConnection.rabbitMQClient.close(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /dist/lib/RabbitMQConnection.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.RabbitMQConnection = void 0; 4 | const RabbitMQClient_1 = require("./RabbitMQClient"); 5 | class RabbitMQConnection { 6 | static getClient() { 7 | if (!RabbitMQConnection.rabbitMQClient) { 8 | throw new Error("RabbitMQ client not initialized. Call connect before accessing the client."); 9 | } 10 | return RabbitMQConnection.rabbitMQClient; 11 | } 12 | static connect(rabbitMQUrl) { 13 | if (!RabbitMQConnection.rabbitMQClient) { 14 | RabbitMQConnection.rabbitMQClient = new RabbitMQClient_1.RabbitMQClient(rabbitMQUrl); 15 | // Additional connection logic if needed 16 | RabbitMQConnection.rabbitMQClient.connect(); 17 | } 18 | } 19 | static close() { 20 | if (!RabbitMQConnection.rabbitMQClient) { 21 | throw new Error("RabbitMQ client not initialized. Call connect before accessing the client."); 22 | } 23 | RabbitMQConnection.rabbitMQClient.close(); 24 | } 25 | } 26 | exports.RabbitMQConnection = RabbitMQConnection; 27 | RabbitMQConnection.rabbitMQClient = null; 28 | //# sourceMappingURL=RabbitMQConnection.js.map -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@kazinaimul/rabbitmq", 3 | "version": "1.0.3", 4 | "description": "This package will help to connect RabbitMQ, publish and consume messages", 5 | "main": "dist/lib/index.js", 6 | "types": "dist/lib/index.d.ts", 7 | "author": "Kazi Naimul Hoque ", 8 | "license": "MIT", 9 | "scripts": { 10 | "build": "rimraf ./dist && tsc", 11 | "lint": "eslint --ext .ts src", 12 | "lint:fix": "eslint --ext .ts lib --fix", 13 | "prepare": "husky install .husky" 14 | }, 15 | "devDependencies": { 16 | "@types/node": "^20.6.0", 17 | "@typescript-eslint/eslint-plugin": "^6.15.0", 18 | "eslint": "^8.13.0", 19 | "eslint-config-airbnb-base": "^15.0.0", 20 | "eslint-config-airbnb-typescript": "^17.0.0", 21 | "eslint-config-prettier": "^8.5.0", 22 | "eslint-import-resolver-typescript": "^2.7.1", 23 | "eslint-plugin-import": "^2.24.2", 24 | "eslint-plugin-prettier": "^4.0.0", 25 | "eslint-plugin-promise": "^6.0.0", 26 | "eslint-webpack-plugin": "^3.1.1", 27 | "husky": "^8.0.3", 28 | "prettier": "^2.6.0", 29 | "prettier-eslint": "^13.0.0" 30 | }, 31 | "dependencies": { 32 | "amqplib": "^0.10.3", 33 | "nodemon": "^2.0.22", 34 | "rimraf": "^5.0.1", 35 | "ts-node": "^10.9.1", 36 | "typescript": "^5.2.2" 37 | }, 38 | "directories": { 39 | "lib": "lib" 40 | }, 41 | "repository": { 42 | "type": "git", 43 | "url": "git+https://github.com/kazi-naimul/rabbitmq.git" 44 | }, 45 | "keywords": [ 46 | "rabbitmq", 47 | "typescript", 48 | "RabbitMQ" 49 | ], 50 | "bugs": { 51 | "url": "https://github.com/kazi-naimul/rabbitmq/issues" 52 | }, 53 | "homepage": "https://github.com/kazi-naimul/rabbitmq#readme" 54 | } 55 | -------------------------------------------------------------------------------- /dist/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@aoyan107/rabbitmq", 3 | "version": "1.0.2", 4 | "description": "This package will help to connect RabbitMQ, publish and consume messages", 5 | "main": "dist/lib/index.js", 6 | "types": "dist/lib/index.d.ts", 7 | "author": "Kazi Naimul Hoque ", 8 | "license": "MIT", 9 | "scripts": { 10 | "build": "rimraf ./dist && tsc", 11 | "lint": "eslint --ext .ts src", 12 | "lint:fix": "eslint --ext .ts lib --fix", 13 | "prepare": "husky install .husky" 14 | }, 15 | "devDependencies": { 16 | "@types/node": "^20.6.0", 17 | "@typescript-eslint/eslint-plugin": "^6.15.0", 18 | "eslint": "^8.13.0", 19 | "eslint-config-airbnb-base": "^15.0.0", 20 | "eslint-config-airbnb-typescript": "^17.0.0", 21 | "eslint-config-prettier": "^8.5.0", 22 | "eslint-import-resolver-typescript": "^2.7.1", 23 | "eslint-plugin-import": "^2.24.2", 24 | "eslint-plugin-prettier": "^4.0.0", 25 | "eslint-plugin-promise": "^6.0.0", 26 | "eslint-webpack-plugin": "^3.1.1", 27 | "husky": "^8.0.3", 28 | "prettier": "^2.6.0", 29 | "prettier-eslint": "^13.0.0" 30 | }, 31 | "dependencies": { 32 | "amqplib": "^0.10.3", 33 | "nodemon": "^2.0.22", 34 | "rimraf": "^5.0.1", 35 | "ts-node": "^10.9.1", 36 | "typescript": "^5.2.2" 37 | }, 38 | "directories": { 39 | "lib": "lib" 40 | }, 41 | "repository": { 42 | "type": "git", 43 | "url": "git+https://github.com/aoyan107/rabbitmq.git" 44 | }, 45 | "keywords": [ 46 | "rabbitmq", 47 | "typescript", 48 | "RabbitMQ" 49 | ], 50 | "bugs": { 51 | "url": "https://github.com/aoyan107/rabbitmq/issues" 52 | }, 53 | "homepage": "https://github.com/aoyan107/rabbitmq#readme" 54 | } 55 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: false, 4 | node: true, 5 | }, 6 | extends: [ 7 | 'airbnb-base', 8 | 'airbnb-typescript/base', 9 | 'plugin:@typescript-eslint/recommended', 10 | 'plugin:promise/recommended', 11 | 'prettier', 12 | ], 13 | parser: '@typescript-eslint/parser', 14 | parserOptions: { 15 | tsconfigRootDir: __dirname, 16 | sourceType: 'module', 17 | project: `${__dirname}/tsconfig.eslint.json`, 18 | }, 19 | plugins: ['@typescript-eslint', 'promise', 'import', 'prettier'], 20 | rules: { 21 | 'prettier/prettier': 'error', 22 | 'import/prefer-default-export': 'off', 23 | 'import/no-default-export': 'off', 24 | 'import/no-dynamic-require': 'off', 25 | 'class-methods-use-this': 'off', 26 | 'no-console': 'off', 27 | 'no-use-before-define': [ 28 | 'error', 29 | { 30 | functions: false, 31 | classes: true, 32 | variables: true, 33 | }, 34 | ], 35 | '@typescript-eslint/explicit-function-return-type': 'off', 36 | '@typescript-eslint/no-use-before-define': [ 37 | 'error', 38 | { 39 | functions: false, 40 | classes: true, 41 | variables: true, 42 | typedefs: true, 43 | }, 44 | ], 45 | 'import/no-extraneous-dependencies': 'off', 46 | // 'no-console': 'off', 47 | 'promise/no-callback-in-promise': 'off', 48 | '@typescript-eslint/no-explicit-any': 'off', 49 | 'array-callback-return': 'off', 50 | 'prefer-promise-reject-errors': 'off', 51 | 'no-empty-pattern': 'off', 52 | 'promise/always-return': 'off', 53 | 'eslint-disable no-plusplus': 'off', 54 | 'no-underscore-dangle': 'off', 55 | }, 56 | settings: { 57 | 'import/resolver': { 58 | typescript: { 59 | alwaysTryTypes: true, 60 | project: `${__dirname}/tsconfig.json`, 61 | }, 62 | }, 63 | }, 64 | }; 65 | -------------------------------------------------------------------------------- /dist/lib/Consumer.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"Consumer.js","sourceRoot":"","sources":["../../lib/Consumer.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /lib/Consumer.ts: -------------------------------------------------------------------------------- 1 | import { RabbitMQClient } from "./RabbitMQClient"; 2 | import { ConsumerOptions } from "./type"; 3 | import { RabbitMQConnection } from "./RabbitMQConnection"; 4 | 5 | export abstract class Consumer { 6 | protected queueName: string; 7 | 8 | protected retry: boolean; 9 | 10 | protected retryCount: number; 11 | 12 | protected retryDelay: number; 13 | 14 | protected rabbitMQClient: RabbitMQClient; 15 | 16 | constructor( 17 | queueName: string, 18 | options: ConsumerOptions = { 19 | retry: true, 20 | retry_count: 3, 21 | retry_delay: 0, 22 | } 23 | ) { 24 | this.queueName = queueName; 25 | this.retry = options.retry; // if it is true message will be queued again when there is an error, by default it is true. 26 | this.retryCount = options.retry_count; // it will retry not more this value, if there is more error it message will be pushed to error queue. 27 | this.retryDelay = options.retry_delay; // it will use this value to as delay value in ms. 28 | this.rabbitMQClient = RabbitMQConnection.getClient(); 29 | } 30 | 31 | abstract execute(message: MessageType): void; 32 | 33 | async consume(): Promise { 34 | try { 35 | await this.rabbitMQClient.connect(); 36 | await this.rabbitMQClient.consume(this.queueName, async (message) => { 37 | try { 38 | if (message) { 39 | const messageContent = JSON.parse(message.content.toString()); 40 | await this.execute(messageContent); 41 | } 42 | return true; 43 | } catch (error: any) { 44 | console.error("Error processing message:", error); 45 | 46 | if (!this.retry) { 47 | return false; 48 | } 49 | 50 | const headers = message?.properties.headers || {}; 51 | let errorCount = headers.ErrorCount || 0; 52 | if (errorCount >= this.retryCount) { 53 | try { 54 | await this.rabbitMQClient.sendToQueue( 55 | `${this.queueName}_error`, 56 | JSON.parse(message.content.toString()), 57 | { 58 | delay: this.retryDelay, 59 | } 60 | ); 61 | } catch (sendError) { 62 | console.error("Error sending message to error queue:", sendError); 63 | } 64 | } else { 65 | errorCount += 1; 66 | try { 67 | await this.rabbitMQClient.sendToQueue( 68 | this.queueName, 69 | JSON.parse(message.content.toString()), 70 | { 71 | persistent: true, 72 | delay: this.retryDelay, 73 | headers: { 74 | ...headers, 75 | ErrorCount: errorCount, 76 | LastException: error.message, 77 | }, 78 | } 79 | ); 80 | } catch (sendError) { 81 | console.error("Error requeueing message:", sendError); 82 | } 83 | } 84 | return false; 85 | } finally { 86 | await this.rabbitMQClient.ack(message); 87 | } 88 | }); 89 | } catch (error) { 90 | console.error("Error consuming messages:", error); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /dist/lib/Consumer.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.Consumer = void 0; 13 | const RabbitMQConnection_1 = require("./RabbitMQConnection"); 14 | class Consumer { 15 | constructor(queueName, options = { 16 | retry: true, 17 | retry_count: 3, 18 | retry_delay: 0, 19 | }) { 20 | this.queueName = queueName; 21 | this.retry = options.retry; // if it is true message will be queued again when there is an error, by default it is true. 22 | this.retryCount = options.retry_count; // it will retry not more this value, if there is more error it message will be pushed to error queue. 23 | this.retryDelay = options.retry_delay; // it will use this value to as delay value in ms. 24 | this.rabbitMQClient = RabbitMQConnection_1.RabbitMQConnection.getClient(); 25 | } 26 | consume() { 27 | return __awaiter(this, void 0, void 0, function* () { 28 | try { 29 | yield this.rabbitMQClient.connect(); 30 | yield this.rabbitMQClient.consume(this.queueName, (message) => __awaiter(this, void 0, void 0, function* () { 31 | try { 32 | if (message) { 33 | const messageContent = JSON.parse(message.content.toString()); 34 | yield this.execute(messageContent); 35 | } 36 | return true; 37 | } 38 | catch (error) { 39 | console.error("Error processing message:", error); 40 | if (!this.retry) { 41 | return false; 42 | } 43 | const headers = (message === null || message === void 0 ? void 0 : message.properties.headers) || {}; 44 | let errorCount = headers.ErrorCount || 0; 45 | if (errorCount >= this.retryCount) { 46 | try { 47 | yield this.rabbitMQClient.sendToQueue(`${this.queueName}_error`, JSON.parse(message.content.toString()), { 48 | delay: this.retryDelay, 49 | }); 50 | } 51 | catch (sendError) { 52 | console.error("Error sending message to error queue:", sendError); 53 | } 54 | } 55 | else { 56 | errorCount += 1; 57 | try { 58 | yield this.rabbitMQClient.sendToQueue(this.queueName, JSON.parse(message.content.toString()), { 59 | persistent: true, 60 | delay: this.retryDelay, 61 | headers: Object.assign(Object.assign({}, headers), { ErrorCount: errorCount, LastException: error.message }), 62 | }); 63 | } 64 | catch (sendError) { 65 | console.error("Error requeueing message:", sendError); 66 | } 67 | } 68 | return false; 69 | } 70 | finally { 71 | yield this.rabbitMQClient.ack(message); 72 | } 73 | })); 74 | } 75 | catch (error) { 76 | console.error("Error consuming messages:", error); 77 | } 78 | }); 79 | } 80 | } 81 | exports.Consumer = Consumer; 82 | //# sourceMappingURL=Consumer.js.map -------------------------------------------------------------------------------- /dist/lib/RabbitMQClient.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"RabbitMQClient.js","sourceRoot":"","sources":["../../lib/RabbitMQClient.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RabbitMQ Helper 2 | 3 | ## Installation 4 | 5 | To integrate the RabbitMQ Helper package into your project, use the following command: 6 | 7 | ```bash 8 | yarn add @kazinaimul/rabbitmq 9 | ``` 10 | 11 | ## RabbitMQ Server 12 | You can use following docker file to create a RabbitMQ server: 13 | ``` 14 | FROM rabbitmq:3.12.0-management 15 | 16 | RUN apt-get update 17 | 18 | RUN apt-get install -y curl 19 | 20 | RUN curl -L https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases/download/v3.12.0/rabbitmq_delayed_message_exchange-3.12.0.ez > $RABBITMQ_HOME/plugins/rabbitmq_delayed_message_exchange-3.12.0.ez 21 | 22 | RUN chown rabbitmq:rabbitmq $RABBITMQ_HOME/plugins/rabbitmq_delayed_message_exchange-3.12.0.ez 23 | 24 | RUN rabbitmq-plugins enable --offline rabbitmq_delayed_message_exchange 25 | 26 | RUN rabbitmq-plugins enable --offline rabbitmq_consistent_hash_exchange 27 | ``` 28 | # To be noted this package requires following plugins to enabled: 29 | rabbitmq_delayed_message_exchange 30 | rabbitmq_consistent_hash_exchange 31 | ## Usage 32 | 33 | ### Establishing Connection 34 | 35 | In your Express app's `app.js` file, establish a connection to RabbitMQ using the following code: 36 | 37 | ```javascript 38 | import { RabbitMQConnection } from '@kazinaimul/rabbitmq'; 39 | 40 | RabbitMQConnection.connect('RABBITMQ_CONNECTION_URL'); 41 | ``` 42 | 43 | Replace `RABBITMQ_CONNECTION_URL` with your RabbitMQ server connection URL, formatted as `amqp://username:password@localhost:5672`. 44 | 45 | ### Publishing a Message 46 | 47 | To publish a message, create a Publisher class by extending the provided `Publisher` class from the package. Here is an example: 48 | 49 | ```javascript 50 | import { Publisher } from '@kazinaimul/rabbitmq'; 51 | 52 | export class PublishMessage extends Publisher { 53 | constructor() { 54 | const queueName = 'queue-name'; 55 | super(queueName); 56 | } 57 | 58 | async publish(message: MessageType): Promise { 59 | try { 60 | const customOptions = { 61 | exchange: `your-exchange_name`, 62 | routingKey: queueName, 63 | delay: 0, 64 | exchangeType: "direct", 65 | headers: {}, 66 | }; // Custom optional values, overwriting default options 67 | await this.rabbitMQClient.publish(this.queueName, message, customOptions); 68 | } catch (error) { 69 | console.error('Error publishing messages:', error); 70 | } 71 | } 72 | } 73 | ``` 74 | 75 | By default, the package uses the following options to publish a message: 76 | 77 | ```javascript 78 | const defaultOptions = { 79 | exchange: `Exchange_${queueName}`, 80 | routingKey: queueName, 81 | delay: 0, 82 | exchangeType: "direct", 83 | headers: {}, 84 | }; 85 | ``` 86 | Here queueName is the given Queue Name while initialize the class. 87 | You can customize these options as needed. 88 | 89 | You can then use this class to publish messages anywhere in your application: 90 | 91 | ```javascript 92 | const publisher = new PublishMessage(); 93 | publisher.publish(publishJson); 94 | ``` 95 | 96 | ### Consuming Messages 97 | 98 | To consume messages, create a Consumer class by extending the provided `Consumer` class from the package. Here is an example: 99 | 100 | ```javascript 101 | import { Consumer } from '@kazinaimul/rabbitmq'; 102 | 103 | export class MyConsumer extends Consumer { 104 | constructor() { 105 | const queueName = 'queue-name'; 106 | const options = { 107 | retry: true, // If true, messages will be queued again in case of an error (default is true) 108 | retry_count: 3, // Maximum retry count, beyond which the message will be moved to an error queue 109 | retry_delay: 0 // Delay in milliseconds for retries 110 | }; 111 | super(queueName, options); // Options is an optional field 112 | } 113 | 114 | async execute(message: T): Promise { 115 | // Implement your own logic to handle the consumed message 116 | } 117 | } 118 | ``` 119 | 120 | Register your consumers in a file (e.g., `consumerRegister.ts`): 121 | 122 | ```javascript 123 | import { MyConsumer } from './MyConsumer'; 124 | 125 | export const consumerRegister: any[] = [new MyConsumer()]; 126 | ``` 127 | 128 | In your application, consume messages by iterating through the registered consumers: 129 | 130 | ```javascript 131 | import { consumerRegister } from './consumerRegister'; 132 | 133 | // Consume messages from registered consumers 134 | for (const consumer of consumerRegister) { 135 | consumer.consume(); 136 | } 137 | ``` 138 | 139 | Now, the `MyConsumer` class will process messages from the specified queue. 140 | 141 | Remember to replace `'queue-name'` with the actual queue name you want to use. 142 | 143 | ## Notes 144 | 145 | - Replace placeholder values and adjust configurations according to your RabbitMQ setup. 146 | - For further customization, refer to the provided classes in the package and their methods. 147 | 148 | Feel free to reach out if you encounter any issues or have questions related to this package. Happy coding! 149 | -------------------------------------------------------------------------------- /lib/RabbitMQClient.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-prototype-builtins */ 2 | /* eslint-disable no-self-assign */ 3 | import * as amqp from "amqplib"; 4 | 5 | declare type Options = { 6 | exchange?: string; 7 | routingKey?: string; 8 | persistent?: boolean; 9 | delay?: number; 10 | exchangeType?: "direct" | "fanout" | "topic"; 11 | headers?: object; 12 | }; 13 | export class RabbitMQClient { 14 | private static connection: amqp.Connection; 15 | 16 | private channel: amqp.Channel; 17 | 18 | public constructor(private url: string) { 19 | this.url = url; 20 | this.channel = this.channel; 21 | } 22 | 23 | getChannel(): amqp.Channel { 24 | return this.channel; 25 | } 26 | 27 | async connect(): Promise { 28 | try { 29 | if (!RabbitMQClient.connection) { 30 | RabbitMQClient.connection = await amqp.connect(this.url); 31 | } 32 | this.channel = await RabbitMQClient.connection.createChannel(); 33 | } catch (error) { 34 | console.error("Error connecting to RabbitMQ:", error); 35 | throw error; 36 | } 37 | } 38 | 39 | async publish( 40 | queue: string, 41 | message: MessageType, 42 | options: Options = {} 43 | ): Promise { 44 | try { 45 | // By default we use following defaultOptions to publish a message. To make sure the message is not consumed by multiple consumer unintentionally we 46 | // are keeping routingKey value same as the queue name. This default options will be always overwritten by the given options. 47 | const defaultOptions: Options = { 48 | exchange: `Exchange_${queue}`, 49 | routingKey: queue, 50 | delay: 0, 51 | exchangeType: "direct", 52 | headers: {}, 53 | }; 54 | const mergedOptions = { ...defaultOptions, ...options }; 55 | 56 | // Declare the delayed exchange 57 | await this.channel.assertExchange( 58 | `${mergedOptions.exchange}-delayed`, 59 | "x-delayed-message", 60 | { 61 | durable: true, 62 | arguments: { 63 | "x-delayed-type": mergedOptions.exchangeType, 64 | }, 65 | } 66 | ); 67 | 68 | // Declare the queue 69 | await this.channel.assertQueue(queue, { durable: true }); 70 | 71 | // Bind the queue to the delayed exchange with the routing key 72 | await this.channel.bindQueue( 73 | queue, 74 | `${mergedOptions.exchange}-delayed`, 75 | mergedOptions.routingKey 76 | ); 77 | 78 | const delayedMessage: amqp.Message = { 79 | properties: { 80 | headers: { 81 | ...mergedOptions.headers, 82 | "x-delay": mergedOptions.delay, 83 | }, 84 | }, 85 | content: Buffer.from(JSON.stringify(message)), 86 | }; 87 | 88 | await this.channel.publish( 89 | `${mergedOptions.exchange}-delayed`, 90 | mergedOptions.routingKey, 91 | delayedMessage.content, 92 | delayedMessage.properties 93 | ); 94 | 95 | console.log("Message published:", message); 96 | } catch (error) { 97 | console.error("Error publishing message:", error); 98 | throw error; 99 | } 100 | } 101 | 102 | async sendToQueue( 103 | queue: string, 104 | message: MessageType, 105 | options: Options = {} 106 | ) { 107 | try { 108 | await this.channel.assertQueue(queue, { durable: true }); 109 | // By default we use following defaultOptions to publish a message. To make sure the message is not consumed by multiple consumer unintentionally we 110 | // are keeping routingKey value same as the queue name. This default options will be always overwritten by the given options. 111 | const defaultOptions: Options = { 112 | exchange: `Exchange_${queue}`, 113 | routingKey: queue, 114 | delay: 0, 115 | exchangeType: "direct", 116 | headers: {}, 117 | }; 118 | const mergedOptions = { ...defaultOptions, ...options }; 119 | if (mergedOptions.delay && mergedOptions.delay > 0) { 120 | await this.channel.assertExchange( 121 | `${mergedOptions.exchange}-delayed`, 122 | "x-delayed-message", 123 | { 124 | durable: true, 125 | arguments: { 126 | "x-delayed-type": mergedOptions.exchangeType, 127 | }, 128 | } 129 | ); 130 | 131 | await this.channel.bindQueue( 132 | queue, 133 | `${mergedOptions.exchange}-delayed`, 134 | mergedOptions.routingKey 135 | ); 136 | const headers = { 137 | "x-delay": mergedOptions.delay, 138 | }; 139 | let mergedHeader = { 140 | ...headers, 141 | }; 142 | 143 | if (options.hasOwnProperty("headers")) { 144 | mergedHeader = { 145 | ...options.headers, 146 | ...headers, 147 | }; 148 | } 149 | const delayedMessage: amqp.Message = { 150 | properties: { 151 | headers: mergedHeader, 152 | }, 153 | content: Buffer.from(JSON.stringify(message)), 154 | }; 155 | 156 | await this.channel.publish( 157 | `${mergedOptions.exchange}-delayed`, 158 | mergedOptions.routingKey, 159 | delayedMessage.content, 160 | delayedMessage.properties 161 | ); 162 | } else { 163 | await this.channel.sendToQueue( 164 | queue, 165 | Buffer.from(JSON.stringify(message)), 166 | options 167 | ); 168 | } 169 | 170 | console.log("Message sent to queue:", queue); 171 | } catch (error) { 172 | console.error("Error sending message to queue:", error); 173 | throw error; 174 | } 175 | } 176 | 177 | async consume( 178 | queue: string, 179 | callback: (message: amqp.ConsumeMessage | null) => void 180 | ): Promise { 181 | try { 182 | await this.channel.assertQueue(queue, { durable: true }); 183 | await this.channel.consume(queue, callback, { noAck: false }); 184 | console.log("Consuming messages from queue:", queue); 185 | } catch (error) { 186 | console.error("Error consuming messages:", error); 187 | throw error; 188 | } 189 | } 190 | 191 | async ack(message: amqp.ConsumeMessage | null): Promise { 192 | try { 193 | if (message) { 194 | if (message) { 195 | this.channel.ack(message); 196 | } 197 | } 198 | } catch (error) { 199 | console.error(error); 200 | throw error; 201 | } 202 | } 203 | 204 | async nack(message: amqp.ConsumeMessage | null): Promise { 205 | if (message) { 206 | await this.channel.nack(message); 207 | } 208 | } 209 | 210 | async getConsumerCount(queue: string): Promise { 211 | try { 212 | const { consumerCount } = await this.channel.assertQueue(queue, { 213 | durable: true, 214 | }); 215 | console.log(`Consumer count for queue "${queue}": ${consumerCount}`); 216 | return consumerCount; 217 | } catch (error) { 218 | console.error("Error getting consumer count:", error); 219 | throw error; 220 | } 221 | } 222 | 223 | async close(): Promise { 224 | try { 225 | if (this.channel) { 226 | await this.channel.close(); 227 | } 228 | if (RabbitMQClient.connection) { 229 | await RabbitMQClient.connection.close(); 230 | } 231 | console.log("Disconnected from RabbitMQ"); 232 | } catch (error) { 233 | console.error("Error closing RabbitMQ connection:", error); 234 | throw error; 235 | } 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /dist/lib/RabbitMQClient.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 26 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 27 | return new (P || (P = Promise))(function (resolve, reject) { 28 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 29 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 30 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 31 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 32 | }); 33 | }; 34 | Object.defineProperty(exports, "__esModule", { value: true }); 35 | exports.RabbitMQClient = void 0; 36 | /* eslint-disable no-prototype-builtins */ 37 | /* eslint-disable no-self-assign */ 38 | const amqp = __importStar(require("amqplib")); 39 | class RabbitMQClient { 40 | constructor(url) { 41 | this.url = url; 42 | this.url = url; 43 | this.channel = this.channel; 44 | } 45 | getChannel() { 46 | return this.channel; 47 | } 48 | connect() { 49 | return __awaiter(this, void 0, void 0, function* () { 50 | try { 51 | if (!RabbitMQClient.connection) { 52 | RabbitMQClient.connection = yield amqp.connect(this.url); 53 | } 54 | this.channel = yield RabbitMQClient.connection.createChannel(); 55 | } 56 | catch (error) { 57 | console.error("Error connecting to RabbitMQ:", error); 58 | throw error; 59 | } 60 | }); 61 | } 62 | publish(queue, message, options = {}) { 63 | return __awaiter(this, void 0, void 0, function* () { 64 | try { 65 | // By default we use following defaultOptions to publish a message. To make sure the message is not consumed by multiple consumer unintentionally we 66 | // are keeping routingKey value same as the queue name. This default options will be always overwritten by the given options. 67 | const defaultOptions = { 68 | exchange: `Exchange_${queue}`, 69 | routingKey: queue, 70 | delay: 0, 71 | exchangeType: "direct", 72 | headers: {}, 73 | }; 74 | const mergedOptions = Object.assign(Object.assign({}, defaultOptions), options); 75 | // Declare the delayed exchange 76 | yield this.channel.assertExchange(`${mergedOptions.exchange}-delayed`, "x-delayed-message", { 77 | durable: true, 78 | arguments: { 79 | "x-delayed-type": mergedOptions.exchangeType, 80 | }, 81 | }); 82 | // Declare the queue 83 | yield this.channel.assertQueue(queue, { durable: true }); 84 | // Bind the queue to the delayed exchange with the routing key 85 | yield this.channel.bindQueue(queue, `${mergedOptions.exchange}-delayed`, mergedOptions.routingKey); 86 | const delayedMessage = { 87 | properties: { 88 | headers: Object.assign(Object.assign({}, mergedOptions.headers), { "x-delay": mergedOptions.delay }), 89 | }, 90 | content: Buffer.from(JSON.stringify(message)), 91 | }; 92 | yield this.channel.publish(`${mergedOptions.exchange}-delayed`, mergedOptions.routingKey, delayedMessage.content, delayedMessage.properties); 93 | console.log("Message published:", message); 94 | } 95 | catch (error) { 96 | console.error("Error publishing message:", error); 97 | throw error; 98 | } 99 | }); 100 | } 101 | sendToQueue(queue, message, options = {}) { 102 | return __awaiter(this, void 0, void 0, function* () { 103 | try { 104 | yield this.channel.assertQueue(queue, { durable: true }); 105 | // By default we use following defaultOptions to publish a message. To make sure the message is not consumed by multiple consumer unintentionally we 106 | // are keeping routingKey value same as the queue name. This default options will be always overwritten by the given options. 107 | const defaultOptions = { 108 | exchange: `Exchange_${queue}`, 109 | routingKey: queue, 110 | delay: 0, 111 | exchangeType: "direct", 112 | headers: {}, 113 | }; 114 | const mergedOptions = Object.assign(Object.assign({}, defaultOptions), options); 115 | if (mergedOptions.delay && mergedOptions.delay > 0) { 116 | yield this.channel.assertExchange(`${mergedOptions.exchange}-delayed`, "x-delayed-message", { 117 | durable: true, 118 | arguments: { 119 | "x-delayed-type": mergedOptions.exchangeType, 120 | }, 121 | }); 122 | yield this.channel.bindQueue(queue, `${mergedOptions.exchange}-delayed`, mergedOptions.routingKey); 123 | const headers = { 124 | "x-delay": mergedOptions.delay, 125 | }; 126 | let mergedHeader = Object.assign({}, headers); 127 | if (options.hasOwnProperty("headers")) { 128 | mergedHeader = Object.assign(Object.assign({}, options.headers), headers); 129 | } 130 | const delayedMessage = { 131 | properties: { 132 | headers: mergedHeader, 133 | }, 134 | content: Buffer.from(JSON.stringify(message)), 135 | }; 136 | yield this.channel.publish(`${mergedOptions.exchange}-delayed`, mergedOptions.routingKey, delayedMessage.content, delayedMessage.properties); 137 | } 138 | else { 139 | yield this.channel.sendToQueue(queue, Buffer.from(JSON.stringify(message)), options); 140 | } 141 | console.log("Message sent to queue:", queue); 142 | } 143 | catch (error) { 144 | console.error("Error sending message to queue:", error); 145 | throw error; 146 | } 147 | }); 148 | } 149 | consume(queue, callback) { 150 | return __awaiter(this, void 0, void 0, function* () { 151 | try { 152 | yield this.channel.assertQueue(queue, { durable: true }); 153 | yield this.channel.consume(queue, callback, { noAck: false }); 154 | console.log("Consuming messages from queue:", queue); 155 | } 156 | catch (error) { 157 | console.error("Error consuming messages:", error); 158 | throw error; 159 | } 160 | }); 161 | } 162 | ack(message) { 163 | return __awaiter(this, void 0, void 0, function* () { 164 | try { 165 | if (message) { 166 | if (message) { 167 | this.channel.ack(message); 168 | } 169 | } 170 | } 171 | catch (error) { 172 | console.error(error); 173 | throw error; 174 | } 175 | }); 176 | } 177 | nack(message) { 178 | return __awaiter(this, void 0, void 0, function* () { 179 | if (message) { 180 | yield this.channel.nack(message); 181 | } 182 | }); 183 | } 184 | getConsumerCount(queue) { 185 | return __awaiter(this, void 0, void 0, function* () { 186 | try { 187 | const { consumerCount } = yield this.channel.assertQueue(queue, { 188 | durable: true, 189 | }); 190 | console.log(`Consumer count for queue "${queue}": ${consumerCount}`); 191 | return consumerCount; 192 | } 193 | catch (error) { 194 | console.error("Error getting consumer count:", error); 195 | throw error; 196 | } 197 | }); 198 | } 199 | close() { 200 | return __awaiter(this, void 0, void 0, function* () { 201 | try { 202 | if (this.channel) { 203 | yield this.channel.close(); 204 | } 205 | if (RabbitMQClient.connection) { 206 | yield RabbitMQClient.connection.close(); 207 | } 208 | console.log("Disconnected from RabbitMQ"); 209 | } 210 | catch (error) { 211 | console.error("Error closing RabbitMQ connection:", error); 212 | throw error; 213 | } 214 | }); 215 | } 216 | } 217 | exports.RabbitMQClient = RabbitMQClient; 218 | //# sourceMappingURL=RabbitMQClient.js.map --------------------------------------------------------------------------------