amqplib 1.1.0 → 1.2.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/.github/workflows/test.yml +3 -0
- package/CHANGELOG.md +6 -0
- package/callback_api.d.ts +209 -0
- package/index.d.ts +171 -0
- package/lefthook.yml +3 -0
- package/lib/properties.d.ts +208 -0
- package/lib/recovery.js +6 -1
- package/package.json +16 -2
- package/test/recovery.test.js +32 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Change log for amqplib
|
|
2
2
|
|
|
3
|
+
## v1.2.0
|
|
4
|
+
- Add bundled TypeScript type definitions (fixes #843)
|
|
5
|
+
|
|
6
|
+
## v1.1.1
|
|
7
|
+
- Forward `handler-error` events from the underlying connection to the recovery wrapper, so listeners attached to `RecoveringPromiseModel`/`RecoveringCallbackModel` receive handler errors
|
|
8
|
+
|
|
3
9
|
## v1.1.0
|
|
4
10
|
- Add connection recovery via `connectWithRecoveryPromise` and `connectWithRecoveryCallback` — automatically reconnects on connection loss with configurable backoff delay, jitter, and retry limits (thanks [@ShiriNmi1520](https://github.com/ShiriNmi1520))
|
|
5
11
|
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import events = require('events');
|
|
2
|
+
import {
|
|
3
|
+
ChannelOptions,
|
|
4
|
+
ConsumeMessage,
|
|
5
|
+
GetMessage,
|
|
6
|
+
Message,
|
|
7
|
+
Options,
|
|
8
|
+
Replies,
|
|
9
|
+
ServerProperties,
|
|
10
|
+
SocketOptions,
|
|
11
|
+
} from './lib/properties';
|
|
12
|
+
export * from './lib/properties';
|
|
13
|
+
|
|
14
|
+
export interface Connection extends events.EventEmitter {
|
|
15
|
+
close(callback?: (err: Error) => void): void;
|
|
16
|
+
createChannel(callback: (err: Error, channel: Channel) => void): Channel;
|
|
17
|
+
createChannel(options: ChannelOptions, callback: (err: Error, channel: Channel) => void): Channel;
|
|
18
|
+
createConfirmChannel(callback: (err: Error, confirmChannel: ConfirmChannel) => void): ConfirmChannel;
|
|
19
|
+
createConfirmChannel(options: ChannelOptions, callback: (err: Error, confirmChannel: ConfirmChannel) => void): ConfirmChannel;
|
|
20
|
+
readonly connection: {
|
|
21
|
+
readonly serverProperties: ServerProperties;
|
|
22
|
+
};
|
|
23
|
+
updateSecret(newSecret: Buffer, reason: string, callback?: (err: Error) => void): void;
|
|
24
|
+
|
|
25
|
+
on(event: 'close', listener: (err?: Error) => void): this;
|
|
26
|
+
on(event: 'error', listener: (err: Error) => void): this;
|
|
27
|
+
on(event: 'blocked', listener: (reason: string) => void): this;
|
|
28
|
+
on(event: 'unblocked', listener: () => void): this;
|
|
29
|
+
on(event: 'update-secret-ok', listener: () => void): this;
|
|
30
|
+
on(event: 'handler-error', listener: (err: Error, eventName: string) => void): this;
|
|
31
|
+
on(event: string, listener: (...args: any[]) => void): this;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface Channel extends events.EventEmitter {
|
|
35
|
+
readonly connection: Connection;
|
|
36
|
+
|
|
37
|
+
on(event: 'close', listener: () => void): this;
|
|
38
|
+
on(event: 'error', listener: (err: Error) => void): this;
|
|
39
|
+
on(event: 'drain', listener: () => void): this;
|
|
40
|
+
on(event: 'ack', listener: (fields: { deliveryTag: number; multiple: boolean }) => void): this;
|
|
41
|
+
on(event: 'nack', listener: (fields: { deliveryTag: number; multiple: boolean; requeue: boolean }) => void): this;
|
|
42
|
+
on(event: 'cancel', listener: (fields: { consumerTag: string }) => void): this;
|
|
43
|
+
on(event: 'delivery', listener: (message: ConsumeMessage) => void): this;
|
|
44
|
+
on(event: 'return', listener: (message: Message) => void): this;
|
|
45
|
+
on(event: 'handler-error', listener: (err: Error, eventName: string) => void): this;
|
|
46
|
+
on(event: string, listener: (...args: any[]) => void): this;
|
|
47
|
+
|
|
48
|
+
close(callback?: (err: Error) => void): void;
|
|
49
|
+
|
|
50
|
+
assertQueue(queue?: string, options?: Options.AssertQueue, callback?: (err: Error, ok: Replies.AssertQueue) => void): void;
|
|
51
|
+
checkQueue(queue: string, callback?: (err: Error, ok: Replies.AssertQueue) => void): void;
|
|
52
|
+
|
|
53
|
+
deleteQueue(queue: string, options?: Options.DeleteQueue, callback?: (err: Error, ok: Replies.DeleteQueue) => void): void;
|
|
54
|
+
purgeQueue(queue: string, callback?: (err: Error, ok: Replies.PurgeQueue) => void): void;
|
|
55
|
+
|
|
56
|
+
bindQueue(
|
|
57
|
+
queue: string,
|
|
58
|
+
source: string,
|
|
59
|
+
pattern: string,
|
|
60
|
+
args?: any,
|
|
61
|
+
callback?: (err: Error, ok: Replies.Empty) => void,
|
|
62
|
+
): void;
|
|
63
|
+
unbindQueue(
|
|
64
|
+
queue: string,
|
|
65
|
+
source: string,
|
|
66
|
+
pattern: string,
|
|
67
|
+
args?: any,
|
|
68
|
+
callback?: (err: Error, ok: Replies.Empty) => void,
|
|
69
|
+
): void;
|
|
70
|
+
|
|
71
|
+
assertExchange(
|
|
72
|
+
exchange: string,
|
|
73
|
+
type: 'direct' | 'topic' | 'headers' | 'fanout' | 'match' | string,
|
|
74
|
+
options?: Options.AssertExchange,
|
|
75
|
+
callback?: (err: Error, ok: Replies.AssertExchange) => void,
|
|
76
|
+
): void;
|
|
77
|
+
checkExchange(exchange: string, callback?: (err: Error, ok: Replies.Empty) => void): void;
|
|
78
|
+
|
|
79
|
+
deleteExchange(exchange: string, options?: Options.DeleteExchange, callback?: (err: Error, ok: Replies.Empty) => void): void;
|
|
80
|
+
|
|
81
|
+
bindExchange(
|
|
82
|
+
destination: string,
|
|
83
|
+
source: string,
|
|
84
|
+
pattern: string,
|
|
85
|
+
args?: any,
|
|
86
|
+
callback?: (err: Error, ok: Replies.Empty) => void,
|
|
87
|
+
): void;
|
|
88
|
+
unbindExchange(
|
|
89
|
+
destination: string,
|
|
90
|
+
source: string,
|
|
91
|
+
pattern: string,
|
|
92
|
+
args?: any,
|
|
93
|
+
callback?: (err: Error, ok: Replies.Empty) => void,
|
|
94
|
+
): void;
|
|
95
|
+
|
|
96
|
+
publish(exchange: string, routingKey: string, content: Buffer, options?: Options.Publish): boolean;
|
|
97
|
+
sendToQueue(queue: string, content: Buffer, options?: Options.Publish): boolean;
|
|
98
|
+
|
|
99
|
+
consume(
|
|
100
|
+
queue: string,
|
|
101
|
+
onMessage: (msg: ConsumeMessage | null) => void,
|
|
102
|
+
options?: Options.Consume,
|
|
103
|
+
callback?: (err: Error, ok: Replies.Consume) => void,
|
|
104
|
+
): void;
|
|
105
|
+
|
|
106
|
+
cancel(consumerTag: string, callback?: (err: Error, ok: Replies.Empty) => void): void;
|
|
107
|
+
get(queue: string, options?: Options.Get, callback?: (err: Error, ok: GetMessage | false) => void): void;
|
|
108
|
+
|
|
109
|
+
ack(message: Message, allUpTo?: boolean): void;
|
|
110
|
+
ackAll(): void;
|
|
111
|
+
|
|
112
|
+
nack(message: Message, allUpTo?: boolean, requeue?: boolean): void;
|
|
113
|
+
nackAll(requeue?: boolean): void;
|
|
114
|
+
reject(message: Message, requeue?: boolean): void;
|
|
115
|
+
|
|
116
|
+
prefetch(count: number, global?: boolean, callback?: (err: Error, ok: Replies.Empty) => void): void;
|
|
117
|
+
recover(callback?: (err: Error, ok: Replies.Empty) => void): void;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface ConfirmChannel extends Channel {
|
|
121
|
+
publish(
|
|
122
|
+
exchange: string,
|
|
123
|
+
routingKey: string,
|
|
124
|
+
content: Buffer,
|
|
125
|
+
options?: Options.Publish,
|
|
126
|
+
callback?: (err: Error, ok: Replies.Empty) => void,
|
|
127
|
+
): boolean;
|
|
128
|
+
sendToQueue(
|
|
129
|
+
queue: string,
|
|
130
|
+
content: Buffer,
|
|
131
|
+
options?: Options.Publish,
|
|
132
|
+
callback?: (err: Error, ok: Replies.Empty) => void,
|
|
133
|
+
): boolean;
|
|
134
|
+
|
|
135
|
+
waitForConfirms(callback?: (err?: Error) => void): void;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export declare class IllegalOperationError extends Error {
|
|
139
|
+
name: 'IllegalOperationError';
|
|
140
|
+
stackAtStateChange: string | undefined;
|
|
141
|
+
constructor(msg: string, stack?: string);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export declare const credentials: {
|
|
145
|
+
plain(username: string, password: string): {
|
|
146
|
+
mechanism: string;
|
|
147
|
+
response(): Buffer;
|
|
148
|
+
username: string;
|
|
149
|
+
password: string;
|
|
150
|
+
};
|
|
151
|
+
amqplain(username: string, password: string): {
|
|
152
|
+
mechanism: string;
|
|
153
|
+
response(): Buffer;
|
|
154
|
+
username: string;
|
|
155
|
+
password: string;
|
|
156
|
+
};
|
|
157
|
+
external(): {
|
|
158
|
+
mechanism: string;
|
|
159
|
+
response(): Buffer;
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
export interface RecoveryOptions {
|
|
164
|
+
/** Initial reconnect delay in milliseconds. Default: 100 */
|
|
165
|
+
initialDelay?: number;
|
|
166
|
+
/** Maximum reconnect delay in milliseconds. Default: 30000 */
|
|
167
|
+
maxDelay?: number;
|
|
168
|
+
/** Backoff multiplier applied to delay on each attempt. Default: 2 */
|
|
169
|
+
factor?: number;
|
|
170
|
+
/** Jitter factor (0–1) applied to delay to avoid thundering herd. Default: 0.2 */
|
|
171
|
+
jitter?: number;
|
|
172
|
+
/** Maximum number of reconnect attempts. Default: Infinity */
|
|
173
|
+
maxRetries?: number;
|
|
174
|
+
/** Optional setup function called after each successful connection */
|
|
175
|
+
setup?: ((model: Connection) => Promise<void>) | ((model: Connection, done: (err?: Error) => void) => void);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface RecoveringConnection extends events.EventEmitter {
|
|
179
|
+
close(callback?: (err: Error) => void): void;
|
|
180
|
+
createChannel(callback: (err: Error, channel: Channel) => void): Channel;
|
|
181
|
+
createChannel(options: ChannelOptions, callback: (err: Error, channel: Channel) => void): Channel;
|
|
182
|
+
createConfirmChannel(callback: (err: Error, confirmChannel: ConfirmChannel) => void): ConfirmChannel;
|
|
183
|
+
createConfirmChannel(options: ChannelOptions, callback: (err: Error, confirmChannel: ConfirmChannel) => void): ConfirmChannel;
|
|
184
|
+
updateSecret(newSecret: Buffer, reason: string, callback?: (err: Error) => void): void;
|
|
185
|
+
|
|
186
|
+
on(event: 'connect', listener: (model: Connection) => void): this;
|
|
187
|
+
on(event: 'disconnect', listener: (err: Error) => void): this;
|
|
188
|
+
on(event: 'connect-failed', listener: (err: Error) => void): this;
|
|
189
|
+
on(event: 'reconnect-scheduled', listener: (info: { attempt: number; delay: number; error: Error }) => void): this;
|
|
190
|
+
on(event: 'reconnect-failed', listener: (err: Error) => void): this;
|
|
191
|
+
on(event: 'blocked', listener: (reason: string) => void): this;
|
|
192
|
+
on(event: 'unblocked', listener: () => void): this;
|
|
193
|
+
on(event: 'error', listener: (err: Error) => void): this;
|
|
194
|
+
on(event: 'update-secret-ok', listener: () => void): this;
|
|
195
|
+
on(event: string, listener: (...args: any[]) => void): this;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export declare function connect(callback: (err: Error, connection: Connection) => void): void;
|
|
199
|
+
export declare function connect(url: string | Options.Connect, callback: (err: Error, connection: Connection) => void): void;
|
|
200
|
+
export declare function connect(
|
|
201
|
+
url: string | Options.Connect,
|
|
202
|
+
socketOptions: SocketOptions,
|
|
203
|
+
callback: (err: Error, connection: Connection) => void,
|
|
204
|
+
): void;
|
|
205
|
+
export declare function connect(
|
|
206
|
+
url: string | Options.Connect,
|
|
207
|
+
socketOptions: SocketOptions & { recovery: RecoveryOptions | true },
|
|
208
|
+
callback: (err: Error, connection: RecoveringConnection) => void,
|
|
209
|
+
): RecoveringConnection;
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import events = require('events');
|
|
2
|
+
import {
|
|
3
|
+
ChannelOptions,
|
|
4
|
+
ConsumeMessage,
|
|
5
|
+
GetMessage,
|
|
6
|
+
Message,
|
|
7
|
+
Options,
|
|
8
|
+
Replies,
|
|
9
|
+
ServerProperties,
|
|
10
|
+
SocketOptions,
|
|
11
|
+
} from './lib/properties';
|
|
12
|
+
export * from './lib/properties';
|
|
13
|
+
|
|
14
|
+
export interface Connection {
|
|
15
|
+
readonly serverProperties: ServerProperties;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ChannelModel extends events.EventEmitter {
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
createChannel(options?: ChannelOptions): Promise<Channel>;
|
|
21
|
+
createConfirmChannel(options?: ChannelOptions): Promise<ConfirmChannel>;
|
|
22
|
+
readonly connection: Connection;
|
|
23
|
+
updateSecret(newSecret: Buffer, reason: string): Promise<void>;
|
|
24
|
+
|
|
25
|
+
on(event: 'close', listener: (err?: Error) => void): this;
|
|
26
|
+
on(event: 'error', listener: (err: Error) => void): this;
|
|
27
|
+
on(event: 'blocked', listener: (reason: string) => void): this;
|
|
28
|
+
on(event: 'unblocked', listener: () => void): this;
|
|
29
|
+
on(event: 'update-secret-ok', listener: () => void): this;
|
|
30
|
+
on(event: 'handler-error', listener: (err: Error, eventName: string) => void): this;
|
|
31
|
+
on(event: string, listener: (...args: any[]) => void): this;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface Channel extends events.EventEmitter {
|
|
35
|
+
readonly connection: Connection;
|
|
36
|
+
|
|
37
|
+
on(event: 'close', listener: () => void): this;
|
|
38
|
+
on(event: 'error', listener: (err: Error) => void): this;
|
|
39
|
+
on(event: 'drain', listener: () => void): this;
|
|
40
|
+
on(event: 'ack', listener: (fields: { deliveryTag: number; multiple: boolean }) => void): this;
|
|
41
|
+
on(event: 'nack', listener: (fields: { deliveryTag: number; multiple: boolean; requeue: boolean }) => void): this;
|
|
42
|
+
on(event: 'cancel', listener: (fields: { consumerTag: string }) => void): this;
|
|
43
|
+
on(event: 'delivery', listener: (message: ConsumeMessage) => void): this;
|
|
44
|
+
on(event: 'return', listener: (message: Message) => void): this;
|
|
45
|
+
on(event: 'handler-error', listener: (err: Error, eventName: string) => void): this;
|
|
46
|
+
on(event: string, listener: (...args: any[]) => void): this;
|
|
47
|
+
|
|
48
|
+
close(): Promise<void>;
|
|
49
|
+
|
|
50
|
+
assertQueue(queue?: string, options?: Options.AssertQueue): Promise<Replies.AssertQueue>;
|
|
51
|
+
checkQueue(queue: string): Promise<Replies.AssertQueue>;
|
|
52
|
+
|
|
53
|
+
deleteQueue(queue: string, options?: Options.DeleteQueue): Promise<Replies.DeleteQueue>;
|
|
54
|
+
purgeQueue(queue: string): Promise<Replies.PurgeQueue>;
|
|
55
|
+
|
|
56
|
+
bindQueue(queue: string, source: string, pattern: string, args?: any): Promise<Replies.Empty>;
|
|
57
|
+
unbindQueue(queue: string, source: string, pattern: string, args?: any): Promise<Replies.Empty>;
|
|
58
|
+
|
|
59
|
+
assertExchange(
|
|
60
|
+
exchange: string,
|
|
61
|
+
type: 'direct' | 'topic' | 'headers' | 'fanout' | 'match' | string,
|
|
62
|
+
options?: Options.AssertExchange,
|
|
63
|
+
): Promise<Replies.AssertExchange>;
|
|
64
|
+
checkExchange(exchange: string): Promise<Replies.Empty>;
|
|
65
|
+
|
|
66
|
+
deleteExchange(exchange: string, options?: Options.DeleteExchange): Promise<Replies.Empty>;
|
|
67
|
+
|
|
68
|
+
bindExchange(destination: string, source: string, pattern: string, args?: any): Promise<Replies.Empty>;
|
|
69
|
+
unbindExchange(destination: string, source: string, pattern: string, args?: any): Promise<Replies.Empty>;
|
|
70
|
+
|
|
71
|
+
publish(exchange: string, routingKey: string, content: Buffer, options?: Options.Publish): boolean;
|
|
72
|
+
sendToQueue(queue: string, content: Buffer, options?: Options.Publish): boolean;
|
|
73
|
+
|
|
74
|
+
consume(
|
|
75
|
+
queue: string,
|
|
76
|
+
onMessage: (msg: ConsumeMessage | null) => void,
|
|
77
|
+
options?: Options.Consume,
|
|
78
|
+
): Promise<Replies.Consume>;
|
|
79
|
+
|
|
80
|
+
cancel(consumerTag: string): Promise<Replies.Empty>;
|
|
81
|
+
get(queue: string, options?: Options.Get): Promise<GetMessage | false>;
|
|
82
|
+
|
|
83
|
+
ack(message: Message, allUpTo?: boolean): void;
|
|
84
|
+
ackAll(): void;
|
|
85
|
+
|
|
86
|
+
nack(message: Message, allUpTo?: boolean, requeue?: boolean): void;
|
|
87
|
+
nackAll(requeue?: boolean): void;
|
|
88
|
+
reject(message: Message, requeue?: boolean): void;
|
|
89
|
+
|
|
90
|
+
prefetch(count: number, global?: boolean): Promise<Replies.Empty>;
|
|
91
|
+
recover(): Promise<Replies.Empty>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface ConfirmChannel extends Channel {
|
|
95
|
+
publish(
|
|
96
|
+
exchange: string,
|
|
97
|
+
routingKey: string,
|
|
98
|
+
content: Buffer,
|
|
99
|
+
options?: Options.Publish,
|
|
100
|
+
callback?: (err: any, ok: Replies.Empty) => void,
|
|
101
|
+
): boolean;
|
|
102
|
+
sendToQueue(
|
|
103
|
+
queue: string,
|
|
104
|
+
content: Buffer,
|
|
105
|
+
options?: Options.Publish,
|
|
106
|
+
callback?: (err: any, ok: Replies.Empty) => void,
|
|
107
|
+
): boolean;
|
|
108
|
+
|
|
109
|
+
waitForConfirms(): Promise<void>;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export declare class IllegalOperationError extends Error {
|
|
113
|
+
name: 'IllegalOperationError';
|
|
114
|
+
stackAtStateChange: string | undefined;
|
|
115
|
+
constructor(msg: string, stack?: string);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export declare const credentials: {
|
|
119
|
+
plain(username: string, password: string): {
|
|
120
|
+
mechanism: string;
|
|
121
|
+
response(): Buffer;
|
|
122
|
+
username: string;
|
|
123
|
+
password: string;
|
|
124
|
+
};
|
|
125
|
+
amqplain(username: string, password: string): {
|
|
126
|
+
mechanism: string;
|
|
127
|
+
response(): Buffer;
|
|
128
|
+
username: string;
|
|
129
|
+
password: string;
|
|
130
|
+
};
|
|
131
|
+
external(): {
|
|
132
|
+
mechanism: string;
|
|
133
|
+
response(): Buffer;
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export interface RecoveryOptions {
|
|
138
|
+
/** Initial reconnect delay in milliseconds. Default: 100 */
|
|
139
|
+
initialDelay?: number;
|
|
140
|
+
/** Maximum reconnect delay in milliseconds. Default: 30000 */
|
|
141
|
+
maxDelay?: number;
|
|
142
|
+
/** Backoff multiplier applied to delay on each attempt. Default: 2 */
|
|
143
|
+
factor?: number;
|
|
144
|
+
/** Jitter factor (0–1) applied to delay to avoid thundering herd. Default: 0.2 */
|
|
145
|
+
jitter?: number;
|
|
146
|
+
/** Maximum number of reconnect attempts. Default: Infinity */
|
|
147
|
+
maxRetries?: number;
|
|
148
|
+
/** Optional setup function called after each successful connection */
|
|
149
|
+
setup?: ((model: ChannelModel) => Promise<void>) | ((model: ChannelModel, done: (err?: Error) => void) => void);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface RecoveringChannelModel extends events.EventEmitter {
|
|
153
|
+
close(): Promise<void>;
|
|
154
|
+
createChannel(options?: ChannelOptions): Promise<Channel>;
|
|
155
|
+
createConfirmChannel(options?: ChannelOptions): Promise<ConfirmChannel>;
|
|
156
|
+
updateSecret(newSecret: Buffer, reason: string): Promise<void>;
|
|
157
|
+
|
|
158
|
+
on(event: 'connect', listener: (model: ChannelModel) => void): this;
|
|
159
|
+
on(event: 'disconnect', listener: (err: Error) => void): this;
|
|
160
|
+
on(event: 'connect-failed', listener: (err: Error) => void): this;
|
|
161
|
+
on(event: 'reconnect-scheduled', listener: (info: { attempt: number; delay: number; error: Error }) => void): this;
|
|
162
|
+
on(event: 'reconnect-failed', listener: (err: Error) => void): this;
|
|
163
|
+
on(event: 'blocked', listener: (reason: string) => void): this;
|
|
164
|
+
on(event: 'unblocked', listener: () => void): this;
|
|
165
|
+
on(event: 'error', listener: (err: Error) => void): this;
|
|
166
|
+
on(event: 'update-secret-ok', listener: () => void): this;
|
|
167
|
+
on(event: string, listener: (...args: any[]) => void): this;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export declare function connect(url: string | Options.Connect, socketOptions: SocketOptions & { recovery: RecoveryOptions | true }): Promise<RecoveringChannelModel>;
|
|
171
|
+
export declare function connect(url: string | Options.Connect, socketOptions?: SocketOptions): Promise<ChannelModel>;
|
package/lefthook.yml
CHANGED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import * as tls from 'tls';
|
|
2
|
+
|
|
3
|
+
export namespace Replies {
|
|
4
|
+
interface Empty {}
|
|
5
|
+
interface AssertQueue {
|
|
6
|
+
queue: string;
|
|
7
|
+
messageCount: number;
|
|
8
|
+
consumerCount: number;
|
|
9
|
+
}
|
|
10
|
+
interface PurgeQueue {
|
|
11
|
+
messageCount: number;
|
|
12
|
+
}
|
|
13
|
+
interface DeleteQueue {
|
|
14
|
+
messageCount: number;
|
|
15
|
+
}
|
|
16
|
+
interface AssertExchange {
|
|
17
|
+
exchange: string;
|
|
18
|
+
}
|
|
19
|
+
interface Consume {
|
|
20
|
+
consumerTag: string;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export namespace Options {
|
|
25
|
+
interface Connect {
|
|
26
|
+
protocol?: string;
|
|
27
|
+
hostname?: string;
|
|
28
|
+
port?: number;
|
|
29
|
+
username?: string;
|
|
30
|
+
password?: string;
|
|
31
|
+
locale?: string;
|
|
32
|
+
frameMax?: number;
|
|
33
|
+
heartbeat?: number;
|
|
34
|
+
vhost?: string;
|
|
35
|
+
channelMax?: number;
|
|
36
|
+
credentials?: {
|
|
37
|
+
mechanism: string;
|
|
38
|
+
response(): Buffer;
|
|
39
|
+
username?: string;
|
|
40
|
+
password?: string;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface AssertQueue {
|
|
45
|
+
exclusive?: boolean;
|
|
46
|
+
durable?: boolean;
|
|
47
|
+
autoDelete?: boolean;
|
|
48
|
+
arguments?: any;
|
|
49
|
+
messageTtl?: number;
|
|
50
|
+
expires?: number;
|
|
51
|
+
deadLetterExchange?: string;
|
|
52
|
+
deadLetterRoutingKey?: string;
|
|
53
|
+
maxLength?: number;
|
|
54
|
+
maxPriority?: number;
|
|
55
|
+
overflow?: string;
|
|
56
|
+
queueMode?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface DeleteQueue {
|
|
60
|
+
ifUnused?: boolean;
|
|
61
|
+
ifEmpty?: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface AssertExchange {
|
|
65
|
+
durable?: boolean;
|
|
66
|
+
internal?: boolean;
|
|
67
|
+
autoDelete?: boolean;
|
|
68
|
+
alternateExchange?: string;
|
|
69
|
+
arguments?: any;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface DeleteExchange {
|
|
73
|
+
ifUnused?: boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
interface Publish {
|
|
77
|
+
expiration?: string | number;
|
|
78
|
+
userId?: string;
|
|
79
|
+
CC?: string | string[];
|
|
80
|
+
mandatory?: boolean;
|
|
81
|
+
persistent?: boolean;
|
|
82
|
+
deliveryMode?: boolean | number;
|
|
83
|
+
BCC?: string | string[];
|
|
84
|
+
contentType?: string;
|
|
85
|
+
contentEncoding?: string;
|
|
86
|
+
headers?: any;
|
|
87
|
+
priority?: number;
|
|
88
|
+
correlationId?: string;
|
|
89
|
+
replyTo?: string;
|
|
90
|
+
messageId?: string;
|
|
91
|
+
timestamp?: number;
|
|
92
|
+
type?: string;
|
|
93
|
+
appId?: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface Consume {
|
|
97
|
+
consumerTag?: string;
|
|
98
|
+
noLocal?: boolean;
|
|
99
|
+
noAck?: boolean;
|
|
100
|
+
exclusive?: boolean;
|
|
101
|
+
priority?: number;
|
|
102
|
+
arguments?: any;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
interface Get {
|
|
106
|
+
noAck?: boolean;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface SocketOptions extends tls.ConnectionOptions {
|
|
111
|
+
noDelay?: boolean;
|
|
112
|
+
timeout?: number;
|
|
113
|
+
keepAlive?: boolean;
|
|
114
|
+
keepAliveDelay?: number;
|
|
115
|
+
clientProperties?: Record<string, unknown>;
|
|
116
|
+
credentials?: {
|
|
117
|
+
mechanism: string;
|
|
118
|
+
response(): Buffer;
|
|
119
|
+
username?: string;
|
|
120
|
+
password?: string;
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface ChannelOptions {
|
|
125
|
+
highWaterMark?: number;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface Message {
|
|
129
|
+
content: Buffer;
|
|
130
|
+
fields: MessageFields;
|
|
131
|
+
properties: MessageProperties;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface GetMessage extends Message {
|
|
135
|
+
fields: GetMessageFields;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface ConsumeMessage extends Message {
|
|
139
|
+
fields: ConsumeMessageFields;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface CommonMessageFields {
|
|
143
|
+
deliveryTag: number;
|
|
144
|
+
redelivered: boolean;
|
|
145
|
+
exchange: string;
|
|
146
|
+
routingKey: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface MessageFields extends CommonMessageFields {
|
|
150
|
+
messageCount?: number;
|
|
151
|
+
consumerTag?: string;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface GetMessageFields extends CommonMessageFields {
|
|
155
|
+
messageCount: number;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface ConsumeMessageFields extends CommonMessageFields {
|
|
159
|
+
consumerTag: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface MessageProperties {
|
|
163
|
+
contentType: any | undefined;
|
|
164
|
+
contentEncoding: any | undefined;
|
|
165
|
+
headers: MessagePropertyHeaders | undefined;
|
|
166
|
+
deliveryMode: any | undefined;
|
|
167
|
+
priority: any | undefined;
|
|
168
|
+
correlationId: any | undefined;
|
|
169
|
+
replyTo: any | undefined;
|
|
170
|
+
expiration: any | undefined;
|
|
171
|
+
messageId: any | undefined;
|
|
172
|
+
timestamp: any | undefined;
|
|
173
|
+
type: any | undefined;
|
|
174
|
+
userId: any | undefined;
|
|
175
|
+
appId: any | undefined;
|
|
176
|
+
clusterId: any | undefined;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export interface MessagePropertyHeaders {
|
|
180
|
+
'x-first-death-exchange'?: string;
|
|
181
|
+
'x-first-death-queue'?: string;
|
|
182
|
+
'x-first-death-reason'?: string;
|
|
183
|
+
'x-death'?: XDeath[];
|
|
184
|
+
[key: string]: any;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface XDeath {
|
|
188
|
+
count: number;
|
|
189
|
+
reason: 'rejected' | 'expired' | 'maxlen';
|
|
190
|
+
queue: string;
|
|
191
|
+
time: {
|
|
192
|
+
'!': 'timestamp';
|
|
193
|
+
value: number;
|
|
194
|
+
};
|
|
195
|
+
exchange: string;
|
|
196
|
+
'original-expiration'?: any;
|
|
197
|
+
'routing-keys': string[];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export interface ServerProperties {
|
|
201
|
+
host: string;
|
|
202
|
+
product: string;
|
|
203
|
+
version: string;
|
|
204
|
+
platform: string;
|
|
205
|
+
copyright?: string;
|
|
206
|
+
information: string;
|
|
207
|
+
[key: string]: string | undefined;
|
|
208
|
+
}
|
package/lib/recovery.js
CHANGED
|
@@ -220,12 +220,14 @@ class RecoveringCore extends EventEmitter {
|
|
|
220
220
|
const onUnblocked = () => this.emit('unblocked');
|
|
221
221
|
const onConnectionError = (err) => this.emit('error', err);
|
|
222
222
|
const onUpdateSecretOk = () => this.emit('update-secret-ok');
|
|
223
|
+
const onHandlerError = (err, event) => this.emit('handler-error', err, event);
|
|
223
224
|
|
|
224
225
|
model.on('close', onClose);
|
|
225
226
|
model.on('blocked', onBlocked);
|
|
226
227
|
model.on('unblocked', onUnblocked);
|
|
227
228
|
model.on('error', onConnectionError);
|
|
228
229
|
model.on('update-secret-ok', onUpdateSecretOk);
|
|
230
|
+
model.on('handler-error', onHandlerError);
|
|
229
231
|
|
|
230
232
|
this._modelListeners = {
|
|
231
233
|
model,
|
|
@@ -234,17 +236,19 @@ class RecoveringCore extends EventEmitter {
|
|
|
234
236
|
onUnblocked,
|
|
235
237
|
onConnectionError,
|
|
236
238
|
onUpdateSecretOk,
|
|
239
|
+
onHandlerError,
|
|
237
240
|
};
|
|
238
241
|
}
|
|
239
242
|
|
|
240
243
|
_unbindModel() {
|
|
241
244
|
if (!this._modelListeners) return;
|
|
242
|
-
const { model, onClose, onBlocked, onUnblocked, onConnectionError, onUpdateSecretOk } = this._modelListeners;
|
|
245
|
+
const { model, onClose, onBlocked, onUnblocked, onConnectionError, onUpdateSecretOk, onHandlerError } = this._modelListeners;
|
|
243
246
|
model.removeListener('close', onClose);
|
|
244
247
|
model.removeListener('blocked', onBlocked);
|
|
245
248
|
model.removeListener('unblocked', onUnblocked);
|
|
246
249
|
model.removeListener('error', onConnectionError);
|
|
247
250
|
model.removeListener('update-secret-ok', onUpdateSecretOk);
|
|
251
|
+
model.removeListener('handler-error', onHandlerError);
|
|
248
252
|
model.on('error', () => {});
|
|
249
253
|
this._modelListeners = null;
|
|
250
254
|
}
|
|
@@ -366,6 +370,7 @@ function wireCommonEvents(source, target) {
|
|
|
366
370
|
'unblocked',
|
|
367
371
|
'error',
|
|
368
372
|
'update-secret-ok',
|
|
373
|
+
'handler-error',
|
|
369
374
|
].forEach((eventName) => {
|
|
370
375
|
source.on(eventName, (...args) => target.emit(eventName, ...args));
|
|
371
376
|
});
|
package/package.json
CHANGED
|
@@ -2,7 +2,18 @@
|
|
|
2
2
|
"name": "amqplib",
|
|
3
3
|
"homepage": "http://amqp-node.github.io/amqplib/",
|
|
4
4
|
"main": "./channel_api.js",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.2.0",
|
|
6
|
+
"types": "./index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./index.d.ts",
|
|
10
|
+
"default": "./channel_api.js"
|
|
11
|
+
},
|
|
12
|
+
"./callback_api": {
|
|
13
|
+
"types": "./callback_api.d.ts",
|
|
14
|
+
"default": "./callback_api.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
6
17
|
"description": "An AMQP 0-9-1 (e.g., RabbitMQ) library and client.",
|
|
7
18
|
"repository": {
|
|
8
19
|
"type": "git",
|
|
@@ -16,8 +27,10 @@
|
|
|
16
27
|
},
|
|
17
28
|
"devDependencies": {
|
|
18
29
|
"@biomejs/biome": "^2.2.2",
|
|
30
|
+
"@types/node": "^25.6.0",
|
|
19
31
|
"claire": "0.4.1",
|
|
20
32
|
"lefthook": "^1.12.3",
|
|
33
|
+
"typescript": "^5.9.3",
|
|
21
34
|
"uglify-js": "2.8.x"
|
|
22
35
|
},
|
|
23
36
|
"scripts": {
|
|
@@ -26,7 +39,8 @@
|
|
|
26
39
|
"rabbitmq-3": "docker run -d --rm --name rabbitmq -p 5672:5672 rabbitmq:3.12-alpine",
|
|
27
40
|
"rabbitmq-4": "docker run -d --rm --name rabbitmq -p 5672:5672 rabbitmq:4.2-alpine",
|
|
28
41
|
"format": "biome format . --write",
|
|
29
|
-
"lint": "biome lint --max-diagnostics=1000 ."
|
|
42
|
+
"lint": "biome lint --max-diagnostics=1000 .",
|
|
43
|
+
"typecheck": "tsc --noEmit -p tsconfig.types.json"
|
|
30
44
|
},
|
|
31
45
|
"keywords": [
|
|
32
46
|
"AMQP",
|
package/test/recovery.test.js
CHANGED
|
@@ -167,6 +167,38 @@ describe('recovery', () => {
|
|
|
167
167
|
assert(client);
|
|
168
168
|
});
|
|
169
169
|
|
|
170
|
+
it('handler-error from underlying model is forwarded to recovery wrapper', async () => {
|
|
171
|
+
const models = [];
|
|
172
|
+
let opened = 0;
|
|
173
|
+
|
|
174
|
+
function openModel() {
|
|
175
|
+
const model = new FakePromiseModel(++opened);
|
|
176
|
+
models.push(model);
|
|
177
|
+
return Promise.resolve(model);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const client = await recovery.connectWithRecoveryPromise(openModel, {
|
|
181
|
+
initialDelay: 1,
|
|
182
|
+
maxDelay: 1,
|
|
183
|
+
jitter: 0,
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const expectedErr = new Error('user close handler explodes');
|
|
187
|
+
|
|
188
|
+
await new Promise((resolve) => {
|
|
189
|
+
client.on('handler-error', (err, event) => {
|
|
190
|
+
assert.strictEqual(err, expectedErr);
|
|
191
|
+
assert.strictEqual(event, 'close');
|
|
192
|
+
resolve();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// Simulate a handler throwing in a 'close' listener on the underlying model
|
|
196
|
+
models[0].emit('handler-error', expectedErr, 'close');
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
await client.close();
|
|
200
|
+
});
|
|
201
|
+
|
|
170
202
|
it('promise recovery fails after max retries', async () => {
|
|
171
203
|
let attempts = 0;
|
|
172
204
|
|