@opra/rabbitmq 1.15.1 → 1.16.1

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.
@@ -6,7 +6,7 @@ const node_zlib_1 = tslib_1.__importDefault(require("node:zlib"));
6
6
  const type_is_1 = tslib_1.__importDefault(require("@browsery/type-is"));
7
7
  const common_1 = require("@opra/common");
8
8
  const core_1 = require("@opra/core");
9
- const amqplib_1 = tslib_1.__importDefault(require("amqplib"));
9
+ const amqp_connection_manager_1 = require("amqp-connection-manager");
10
10
  const content_type_1 = require("content-type");
11
11
  const iconv_lite_1 = tslib_1.__importDefault(require("iconv-lite"));
12
12
  const util_1 = require("util");
@@ -34,7 +34,6 @@ class RabbitmqAdapter extends core_1.PlatformAdapter {
34
34
  constructor(document, config) {
35
35
  super(config);
36
36
  this._controllerInstances = new Map();
37
- this._connections = [];
38
37
  this._status = 'idle';
39
38
  this.protocol = 'rpc';
40
39
  this.platform = RabbitmqAdapter.PlatformName;
@@ -102,55 +101,54 @@ class RabbitmqAdapter extends core_1.PlatformAdapter {
102
101
  handlerArgs.push(args);
103
102
  }
104
103
  }
105
- /** Connect to server */
106
- for (const connectionOptions of this._config.connection) {
107
- const connection = await amqplib_1.default.connect(connectionOptions).catch(e => {
108
- e.message = 'Unable to connect to RabbitMQ server';
109
- throw new Error('Unable to connect to RabbitMQ server (' +
110
- (typeof connectionOptions == 'object'
111
- ? connectionOptions.hostname + ':' + connectionOptions.port
112
- : connectionOptions) +
113
- ')',
114
- // @ts-ignore
115
- e);
116
- });
117
- this._connections.push(connection);
118
- const hostname = typeof connectionOptions === 'object'
119
- ? connectionOptions.hostname
120
- : connectionOptions;
121
- this.logger?.info?.(`Connected to ${hostname}`);
122
- /** Subscribe to channels */
123
- for (const args of handlerArgs) {
124
- /** Create channel per operation */
125
- const channel = await connection.createChannel();
126
- for (const topic of args.topics) {
127
- const opts = this._config.queues?.[topic];
128
- if (opts)
129
- await channel.assertQueue(topic, opts);
104
+ const connectionOptions = typeof this._config.connection === 'string'
105
+ ? {
106
+ urls: [this._config.connection],
107
+ }
108
+ : Array.isArray(this._config.connection)
109
+ ? {
110
+ urls: this._config.connection,
130
111
  }
131
- for (const topic of args.topics) {
132
- await channel.assertQueue(topic);
133
- await channel
134
- .consume(topic, async (msg) => {
135
- if (!msg)
136
- return;
137
- await this.emitAsync('message', msg, topic).catch(noOp);
138
- try {
139
- await args.handler(channel, topic, msg);
140
- }
141
- catch (e) {
112
+ : this._config.connection;
113
+ this._client = new amqp_connection_manager_1.AmqpConnectionManagerClass(connectionOptions.urls, connectionOptions);
114
+ this._client.connect().catch(e => {
115
+ e.message =
116
+ 'Unable to connect to RabbitMQ server at ' +
117
+ connectionOptions.urls +
118
+ '. ' +
119
+ e.message;
120
+ throw e;
121
+ });
122
+ this.logger?.info?.(`Connected RabbitMQ at ${connectionOptions.urls}`);
123
+ for (const args of handlerArgs) {
124
+ /** Create channel per operation */
125
+ this._client.createChannel({
126
+ setup: async (channel) => {
127
+ for (const topic of args.topics) {
128
+ const opts = this._config.queues?.[topic];
129
+ await channel.assertQueue(topic, opts);
130
+ await channel
131
+ .consume(topic, async (msg) => {
132
+ if (!msg)
133
+ return;
134
+ await this.emitAsync('message', msg, topic).catch(noOp);
135
+ try {
136
+ await args.handler(channel, topic, msg);
137
+ }
138
+ catch (e) {
139
+ this._emitError(e);
140
+ }
141
+ },
142
+ /** Consume options */
143
+ args.operationConfig.consumer)
144
+ .catch(e => {
142
145
  this._emitError(e);
143
- }
144
- },
145
- /** Consume options */
146
- args.operationConfig.consumer)
147
- .catch(e => {
148
- this._emitError(e);
149
- throw e;
150
- });
151
- this.logger?.info?.(`Subscribed to topic${args.topics.length > 1 ? 's' : ''} "${args.topics}"`);
152
- }
153
- }
146
+ throw e;
147
+ });
148
+ this.logger?.info?.(`Subscribed to topic${args.topics.length > 1 ? 's' : ''} "${args.topics}"`);
149
+ }
150
+ },
151
+ });
154
152
  }
155
153
  this._status = 'started';
156
154
  }
@@ -163,8 +161,8 @@ class RabbitmqAdapter extends core_1.PlatformAdapter {
163
161
  * Closes all connections and stops the service
164
162
  */
165
163
  async close() {
166
- await Promise.all(this._connections.map(c => c.close()));
167
- this._connections = [];
164
+ await this._client?.close();
165
+ this._client = undefined;
168
166
  this._controllerInstances.clear();
169
167
  this._status = 'idle';
170
168
  }
@@ -187,7 +185,7 @@ class RabbitmqAdapter extends core_1.PlatformAdapter {
187
185
  return;
188
186
  const operationConfig = {
189
187
  consumer: {
190
- noAck: false,
188
+ noAck: true,
191
189
  },
192
190
  };
193
191
  if (this._config.defaults) {
@@ -2,7 +2,7 @@ import zlib from 'node:zlib';
2
2
  import typeIs from '@browsery/type-is';
3
3
  import { OpraException, RPC_CONTROLLER_METADATA, RpcApi, } from '@opra/common';
4
4
  import { kAssetCache, PlatformAdapter } from '@opra/core';
5
- import amqplib from 'amqplib';
5
+ import { AmqpConnectionManagerClass, } from 'amqp-connection-manager';
6
6
  import { parse as parseContentType } from 'content-type';
7
7
  import iconv from 'iconv-lite';
8
8
  import { promisify } from 'util';
@@ -30,7 +30,6 @@ export class RabbitmqAdapter extends PlatformAdapter {
30
30
  constructor(document, config) {
31
31
  super(config);
32
32
  this._controllerInstances = new Map();
33
- this._connections = [];
34
33
  this._status = 'idle';
35
34
  this.protocol = 'rpc';
36
35
  this.platform = RabbitmqAdapter.PlatformName;
@@ -98,55 +97,54 @@ export class RabbitmqAdapter extends PlatformAdapter {
98
97
  handlerArgs.push(args);
99
98
  }
100
99
  }
101
- /** Connect to server */
102
- for (const connectionOptions of this._config.connection) {
103
- const connection = await amqplib.connect(connectionOptions).catch(e => {
104
- e.message = 'Unable to connect to RabbitMQ server';
105
- throw new Error('Unable to connect to RabbitMQ server (' +
106
- (typeof connectionOptions == 'object'
107
- ? connectionOptions.hostname + ':' + connectionOptions.port
108
- : connectionOptions) +
109
- ')',
110
- // @ts-ignore
111
- e);
112
- });
113
- this._connections.push(connection);
114
- const hostname = typeof connectionOptions === 'object'
115
- ? connectionOptions.hostname
116
- : connectionOptions;
117
- this.logger?.info?.(`Connected to ${hostname}`);
118
- /** Subscribe to channels */
119
- for (const args of handlerArgs) {
120
- /** Create channel per operation */
121
- const channel = await connection.createChannel();
122
- for (const topic of args.topics) {
123
- const opts = this._config.queues?.[topic];
124
- if (opts)
125
- await channel.assertQueue(topic, opts);
100
+ const connectionOptions = typeof this._config.connection === 'string'
101
+ ? {
102
+ urls: [this._config.connection],
103
+ }
104
+ : Array.isArray(this._config.connection)
105
+ ? {
106
+ urls: this._config.connection,
126
107
  }
127
- for (const topic of args.topics) {
128
- await channel.assertQueue(topic);
129
- await channel
130
- .consume(topic, async (msg) => {
131
- if (!msg)
132
- return;
133
- await this.emitAsync('message', msg, topic).catch(noOp);
134
- try {
135
- await args.handler(channel, topic, msg);
136
- }
137
- catch (e) {
108
+ : this._config.connection;
109
+ this._client = new AmqpConnectionManagerClass(connectionOptions.urls, connectionOptions);
110
+ this._client.connect().catch(e => {
111
+ e.message =
112
+ 'Unable to connect to RabbitMQ server at ' +
113
+ connectionOptions.urls +
114
+ '. ' +
115
+ e.message;
116
+ throw e;
117
+ });
118
+ this.logger?.info?.(`Connected RabbitMQ at ${connectionOptions.urls}`);
119
+ for (const args of handlerArgs) {
120
+ /** Create channel per operation */
121
+ this._client.createChannel({
122
+ setup: async (channel) => {
123
+ for (const topic of args.topics) {
124
+ const opts = this._config.queues?.[topic];
125
+ await channel.assertQueue(topic, opts);
126
+ await channel
127
+ .consume(topic, async (msg) => {
128
+ if (!msg)
129
+ return;
130
+ await this.emitAsync('message', msg, topic).catch(noOp);
131
+ try {
132
+ await args.handler(channel, topic, msg);
133
+ }
134
+ catch (e) {
135
+ this._emitError(e);
136
+ }
137
+ },
138
+ /** Consume options */
139
+ args.operationConfig.consumer)
140
+ .catch(e => {
138
141
  this._emitError(e);
139
- }
140
- },
141
- /** Consume options */
142
- args.operationConfig.consumer)
143
- .catch(e => {
144
- this._emitError(e);
145
- throw e;
146
- });
147
- this.logger?.info?.(`Subscribed to topic${args.topics.length > 1 ? 's' : ''} "${args.topics}"`);
148
- }
149
- }
142
+ throw e;
143
+ });
144
+ this.logger?.info?.(`Subscribed to topic${args.topics.length > 1 ? 's' : ''} "${args.topics}"`);
145
+ }
146
+ },
147
+ });
150
148
  }
151
149
  this._status = 'started';
152
150
  }
@@ -159,8 +157,8 @@ export class RabbitmqAdapter extends PlatformAdapter {
159
157
  * Closes all connections and stops the service
160
158
  */
161
159
  async close() {
162
- await Promise.all(this._connections.map(c => c.close()));
163
- this._connections = [];
160
+ await this._client?.close();
161
+ this._client = undefined;
164
162
  this._controllerInstances.clear();
165
163
  this._status = 'idle';
166
164
  }
@@ -183,7 +181,7 @@ export class RabbitmqAdapter extends PlatformAdapter {
183
181
  return;
184
182
  const operationConfig = {
185
183
  consumer: {
186
- noAck: false,
184
+ noAck: true,
187
185
  },
188
186
  };
189
187
  if (this._config.defaults) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opra/rabbitmq",
3
- "version": "1.15.1",
3
+ "version": "1.16.1",
4
4
  "description": "Opra RabbitMQ package",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
@@ -13,8 +13,9 @@
13
13
  "valgen": "^5.15.0"
14
14
  },
15
15
  "peerDependencies": {
16
- "@opra/common": "^1.15.1",
17
- "@opra/core": "^1.15.1",
16
+ "@opra/common": "^1.16.1",
17
+ "@opra/core": "^1.16.1",
18
+ "amqp-connection-manager": "^4.1.14",
18
19
  "amqplib": "^0.10.7"
19
20
  },
20
21
  "type": "module",
@@ -1,6 +1,7 @@
1
1
  import { ApiDocument, OpraException, OpraSchema, RpcApi, RpcController, RpcOperation } from '@opra/common';
2
2
  import { PlatformAdapter } from '@opra/core';
3
- import amqplib, { Channel } from 'amqplib';
3
+ import { type AmqpConnectionManager, type AmqpConnectionManagerOptions, type ChannelWrapper, type ConnectionUrl } from 'amqp-connection-manager';
4
+ import amqplib from 'amqplib';
4
5
  import { ConsumeMessage } from 'amqplib/properties';
5
6
  import { RabbitmqContext } from './rabbitmq-context.js';
6
7
  export interface OperationConfig {
@@ -12,7 +13,7 @@ interface HandlerArguments {
12
13
  instance: any;
13
14
  operation: RpcOperation;
14
15
  operationConfig: OperationConfig;
15
- handler: (channel: Channel, queue: string, msg: ConsumeMessage | null) => void | Promise<void>;
16
+ handler: (channel: ChannelWrapper, queue: string, msg: ConsumeMessage | null) => void | Promise<void>;
16
17
  topics: string[];
17
18
  }
18
19
  /**
@@ -23,7 +24,7 @@ export declare class RabbitmqAdapter extends PlatformAdapter<RabbitmqAdapter.Eve
23
24
  static readonly PlatformName = "rabbitmq";
24
25
  protected _config: RabbitmqAdapter.Config;
25
26
  protected _controllerInstances: Map<RpcController, any>;
26
- protected _connections: amqplib.ChannelModel[];
27
+ protected _client?: AmqpConnectionManager;
27
28
  protected _status: RabbitmqAdapter.Status;
28
29
  readonly protocol: OpraSchema.Transport;
29
30
  readonly platform = "rabbitmq";
@@ -71,9 +72,11 @@ export declare class RabbitmqAdapter extends PlatformAdapter<RabbitmqAdapter.Eve
71
72
  export declare namespace RabbitmqAdapter {
72
73
  type NextCallback = () => Promise<any>;
73
74
  type Status = 'idle' | 'starting' | 'started';
74
- type ConnectionOptions = amqplib.Options.Connect;
75
+ interface ConnectionOptions extends AmqpConnectionManagerOptions {
76
+ urls?: ConnectionUrl[];
77
+ }
75
78
  interface Config extends PlatformAdapter.Options {
76
- connection: (string | ConnectionOptions)[];
79
+ connection: string | string[] | ConnectionOptions;
77
80
  queues?: Record<string, amqplib.Options.AssertQueue>;
78
81
  defaults?: {
79
82
  consumer?: amqplib.Options.Consume;
@@ -1,6 +1,6 @@
1
1
  import { OpraSchema, RpcController, RpcOperation } from '@opra/common';
2
2
  import { ExecutionContext } from '@opra/core';
3
- import type { Channel } from 'amqplib';
3
+ import type { ChannelWrapper } from 'amqp-connection-manager';
4
4
  import type { ConsumeMessage } from 'amqplib/properties';
5
5
  import type { AsyncEventEmitter } from 'node-events-async';
6
6
  import type { RabbitmqAdapter } from './rabbitmq-adapter';
@@ -18,7 +18,7 @@ export declare class RabbitmqContext extends ExecutionContext implements AsyncEv
18
18
  readonly operation?: RpcOperation;
19
19
  readonly operationHandler?: Function;
20
20
  readonly queue: string;
21
- readonly channel: Channel;
21
+ readonly channel: ChannelWrapper;
22
22
  readonly message: ConsumeMessage;
23
23
  readonly content: any;
24
24
  readonly headers: Record<string, any>;
@@ -27,15 +27,15 @@ export declare class RabbitmqContext extends ExecutionContext implements AsyncEv
27
27
  * @param init the context options
28
28
  */
29
29
  constructor(init: RabbitmqContext.Initiator);
30
- get properties(): import("amqplib").MessageProperties;
31
- get fields(): import("amqplib").ConsumeMessageFields;
30
+ get properties(): import("amqplib/properties").MessageProperties;
31
+ get fields(): import("amqplib/properties").ConsumeMessageFields;
32
32
  ack(): void;
33
33
  nack(): void;
34
34
  }
35
35
  export declare namespace RabbitmqContext {
36
36
  interface Initiator extends Omit<ExecutionContext.Initiator, 'document' | 'protocol' | 'documentNode'> {
37
37
  adapter: RabbitmqAdapter;
38
- channel: Channel;
38
+ channel: ChannelWrapper;
39
39
  controller?: RpcController;
40
40
  controllerInstance?: any;
41
41
  operation?: RpcOperation;