rascal 17.0.0 → 17.0.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.
- package/CHANGELOG.md +4 -0
- package/lib/amqp/SubscriberError.js +52 -28
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -68,13 +68,12 @@ module.exports = function SubscriptionRecovery(broker, vhost) {
|
|
|
68
68
|
execute(session, message, err, strategyConfig, next) {
|
|
69
69
|
debug('Republishing message: %s', message.properties.messageId);
|
|
70
70
|
|
|
71
|
-
const once = _.once(next);
|
|
72
71
|
const originalQueue = _.get(message, 'properties.headers.rascal.originalQueue');
|
|
73
72
|
const republished = _.get(message, ['properties', 'headers', 'rascal', 'recovery', originalQueue, 'republished'], 0);
|
|
74
73
|
|
|
75
74
|
if (strategyConfig.attempts && strategyConfig.attempts <= republished) {
|
|
76
75
|
debug('Skipping recovery - message: %s has already been republished %d times.', message.properties.messageId, republished);
|
|
77
|
-
return
|
|
76
|
+
return next(null, false);
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
const publishOptions = _.cloneDeep(message.properties);
|
|
@@ -87,33 +86,50 @@ module.exports = function SubscriptionRecovery(broker, vhost) {
|
|
|
87
86
|
|
|
88
87
|
if (strategyConfig.immediateNack) _.set(publishOptions, ['headers', 'rascal', 'recovery', originalQueue, 'immediateNack'], true);
|
|
89
88
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
});
|
|
96
|
-
};
|
|
89
|
+
const ackMessage = () => {
|
|
90
|
+
session._ack(message, (err) => {
|
|
91
|
+
next(err, true);
|
|
92
|
+
});
|
|
93
|
+
};
|
|
97
94
|
|
|
98
|
-
|
|
95
|
+
const nackMessage = (err) => {
|
|
96
|
+
session._nack(message, (_nackErr) => {
|
|
97
|
+
// nackError just means the channel was already closed meaning the original message would have been rolled back
|
|
98
|
+
next(err);
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const ackOrNack = _.once((err) => {
|
|
103
|
+
return err ? nackMessage(err) : ackMessage();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
vhost.getConfirmChannel((err, publisherChannel) => {
|
|
107
|
+
if (err) return ackOrNack(err);
|
|
99
108
|
|
|
100
|
-
if (!publisherChannel) return
|
|
109
|
+
if (!publisherChannel) return ackOrNack(new Error('Unable to handle subscriber error by republishing. The VHost is shutting down'));
|
|
101
110
|
|
|
102
111
|
publisherChannel.on('error', (err) => {
|
|
103
|
-
|
|
112
|
+
ackOrNack(err);
|
|
104
113
|
});
|
|
114
|
+
|
|
105
115
|
publisherChannel.on('return', () => {
|
|
106
|
-
|
|
116
|
+
ackOrNack(new Error(format('Message: %s was republished to queue: %s, but was returned', message.properties.messageId, originalQueue)));
|
|
107
117
|
});
|
|
108
118
|
|
|
109
119
|
publisherChannel.publish(undefined, originalQueue, message.content, publishOptions, (err) => {
|
|
110
|
-
if (err)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
120
|
+
if (err) {
|
|
121
|
+
// Channel will already be closed, reclosing will trigger an error
|
|
122
|
+
publisherChannel.removeAllListeners();
|
|
123
|
+
|
|
124
|
+
debug('Message: %s failed to be republished to queue: %s %d times - %s', message.properties.messageId, originalQueue, republished + 1, err.message);
|
|
125
|
+
ackOrNack(err);
|
|
126
|
+
} else {
|
|
127
|
+
publisherChannel.close();
|
|
128
|
+
publisherChannel.removeAllListeners();
|
|
129
|
+
|
|
130
|
+
debug('Message: %s was republished to queue: %s %d times', message.properties.messageId, originalQueue, republished + 1);
|
|
131
|
+
ackOrNack();
|
|
132
|
+
}
|
|
117
133
|
});
|
|
118
134
|
});
|
|
119
135
|
},
|
|
@@ -123,13 +139,12 @@ module.exports = function SubscriptionRecovery(broker, vhost) {
|
|
|
123
139
|
execute(session, message, err, strategyConfig, next) {
|
|
124
140
|
debug('Forwarding message: %s to publication: %s', message.properties.messageId, strategyConfig.publication);
|
|
125
141
|
|
|
126
|
-
const once = _.once(next);
|
|
127
142
|
const originalQueue = _.get(message, 'properties.headers.rascal.originalQueue');
|
|
128
143
|
const forwarded = _.get(message, ['properties', 'headers', 'rascal', 'recovery', originalQueue, 'forwarded'], 0);
|
|
129
144
|
|
|
130
145
|
if (strategyConfig.attempts && strategyConfig.attempts <= forwarded) {
|
|
131
146
|
debug('Skipping recovery - message: %s has already been forwarded %d times.', message.properties.messageId, forwarded);
|
|
132
|
-
return
|
|
147
|
+
return next(null, false);
|
|
133
148
|
}
|
|
134
149
|
|
|
135
150
|
// See https://github.com/rabbitmq/rabbitmq-server/issues/161
|
|
@@ -141,30 +156,39 @@ module.exports = function SubscriptionRecovery(broker, vhost) {
|
|
|
141
156
|
_.set(forwardOverrides, 'options.headers.rascal.error.message', _.truncate(err.message, { length: 1024 }));
|
|
142
157
|
_.set(forwardOverrides, 'options.headers.rascal.error.code', err.code);
|
|
143
158
|
|
|
159
|
+
const ackMessage = () => {
|
|
160
|
+
session._ack(message, (err) => {
|
|
161
|
+
next(err, true);
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
|
|
144
165
|
const nackMessage = (err) => {
|
|
145
166
|
session._nack(message, (_nackErr) => {
|
|
146
167
|
// nackError just means the channel was already closed meaning the original message would have been rolled back
|
|
147
|
-
|
|
168
|
+
next(err);
|
|
148
169
|
});
|
|
149
170
|
};
|
|
150
171
|
|
|
172
|
+
const ackOrNack = _.once((err) => {
|
|
173
|
+
return err ? nackMessage(err) : ackMessage();
|
|
174
|
+
});
|
|
175
|
+
|
|
151
176
|
broker.forward(strategyConfig.publication, message, forwardOverrides, (err, publication) => {
|
|
152
177
|
if (err) return nackMessage(err);
|
|
153
178
|
|
|
154
179
|
publication.on('success', () => {
|
|
155
180
|
debug('Message: %s was forwarded to publication: %s %d times', message.properties.messageId, strategyConfig.publication, forwarded + 1);
|
|
156
|
-
|
|
157
|
-
once(ackErr, true);
|
|
158
|
-
});
|
|
181
|
+
ackOrNack();
|
|
159
182
|
});
|
|
160
183
|
|
|
161
184
|
publication.on('error', (err) => {
|
|
162
|
-
|
|
185
|
+
debug('Message: %s failed to be forwarded to publication: %s %d times - %s', message.properties.messageId, strategyConfig.publication, forwarded + 1, err.message);
|
|
186
|
+
ackOrNack(err);
|
|
163
187
|
});
|
|
164
188
|
|
|
165
189
|
publication.on('return', () => {
|
|
166
190
|
publication.removeAllListeners('success');
|
|
167
|
-
|
|
191
|
+
ackOrNack(new Error(format('Message: %s was forwarded to publication: %s, but was returned', message.properties.messageId, strategyConfig.publication)));
|
|
168
192
|
});
|
|
169
193
|
});
|
|
170
194
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rascal",
|
|
3
|
-
"version": "17.0.
|
|
3
|
+
"version": "17.0.1",
|
|
4
4
|
"description": "A config driven wrapper for amqplib supporting multi-host connections, automatic error recovery, redelivery flood protection, transparent encryption / decryption, channel pooling and publication timeouts",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"dependencies": {
|