@palmetto/pubsub 2.2.3 → 2.2.5

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.
@@ -14,6 +14,7 @@ const interfaces_js_1 = require("../interfaces.js");
14
14
  const connection_js_1 = require("./connection.js");
15
15
  const lazy_load_js_1 = require("../lazy-load.js");
16
16
  const create_log_error_payload_js_1 = require("../create-log-error-payload.js");
17
+ const dd_trace_wrapper_js_1 = require("../dd-trace.wrapper.js");
17
18
  class SubscribedMessage {
18
19
  constructor(owner, worker, logger) {
19
20
  this.owner = owner;
@@ -64,20 +65,24 @@ class BullMqSubscriber {
64
65
  context: "BullMqSubscriber",
65
66
  });
66
67
  const worker = new BullMqPackage.Worker(config.name, (job) => __awaiter(this, void 0, void 0, function* () {
67
- const context = {
68
- job: job.name,
69
- retries: job.attemptsMade,
70
- firstSent: new Date(job.timestamp),
71
- // lastSent: new Date(job.attemptsStarted),
72
- };
73
- const result = yield onMessage(job.data, context);
74
- if (result === interfaces_js_1.MessageResult.Ok) {
75
- return context.reply;
76
- }
77
- if (result === interfaces_js_1.MessageResult.Retry) {
78
- throw new MessageRetryError();
79
- }
80
- throw new BullMqPackage.UnrecoverableError("Handler asked to fail this job");
68
+ return yield (0, dd_trace_wrapper_js_1.getTracer)().trace("pubsub.bullmq.handle", {
69
+ resource: `handle ${config.name}`,
70
+ }, () => __awaiter(this, void 0, void 0, function* () {
71
+ const context = {
72
+ job: job.name,
73
+ retries: job.attemptsMade,
74
+ firstSent: new Date(job.timestamp),
75
+ // lastSent: new Date(job.attemptsStarted),
76
+ };
77
+ const result = yield onMessage(job.data, context);
78
+ if (result === interfaces_js_1.MessageResult.Ok) {
79
+ return context.reply;
80
+ }
81
+ if (result === interfaces_js_1.MessageResult.Retry) {
82
+ throw new MessageRetryError();
83
+ }
84
+ throw new BullMqPackage.UnrecoverableError("Handler asked to fail this job");
85
+ }));
81
86
  }), {
82
87
  connection: this.connection,
83
88
  autorun: false,
@@ -1,4 +1,4 @@
1
- interface Span {
1
+ export interface Span {
2
2
  /**
3
3
  * Adds a single tag to the span. See `addTags()` for details.
4
4
  *
@@ -8,6 +8,7 @@ export declare class Publisher {
8
8
  removeProvider(providerOrTransport: PublisherProvider | string): boolean;
9
9
  init(config: PubSubConfiguration): Promise<void>;
10
10
  publish(config: PubSubConfiguration, message: BaseMessage | BaseMessage[]): Promise<void>;
11
+ private publishImpl;
11
12
  close(): Promise<void>;
12
13
  private getProvider;
13
14
  private assertSchema;
package/dist/publisher.js CHANGED
@@ -53,74 +53,64 @@ class Publisher {
53
53
  });
54
54
  }
55
55
  publish(config, message) {
56
+ const messages = Array.isArray(message) ? message : [message];
57
+ return (0, dd_trace_wrapper_js_1.getTracer)().trace("pubsub.publish", {
58
+ resource: `publish ${config.transport} ${config.name}`,
59
+ }, (span) => {
60
+ return this.publishImpl(config, messages, span);
61
+ });
62
+ }
63
+ publishImpl(config, messages, span) {
56
64
  return __awaiter(this, void 0, void 0, function* () {
57
- yield (0, dd_trace_wrapper_js_1.getTracer)().trace("pubsub.publish", {
58
- resource: config.name,
59
- tags: {
60
- "pubsub.transport": config.transport,
61
- },
62
- }, (span) => __awaiter(this, void 0, void 0, function* () {
63
- try {
64
- const provider = this.getProvider(config);
65
- const { schema, schemaId } = this.assertSchema(config);
66
- if (!Array.isArray(message)) {
67
- message = [message];
68
- }
69
- const jsons = message.map((msg) => {
70
- if (!msg.id) {
71
- msg.id = (0, uuid_1.v4)();
72
- }
73
- if (!msg.meta) {
74
- msg.meta = {
75
- createdAt: new Date().toISOString(),
76
- publishedBy: "",
77
- schemaId: schemaId,
78
- };
79
- }
80
- else {
81
- msg.meta.schemaId = schemaId;
82
- }
83
- const check = schema.safeEncode(msg);
84
- if (!check.success) {
85
- (0, message_logger_js_1.logMessage)({
86
- note: "Publish message failed schema validation",
87
- message: message,
88
- level: "error",
89
- logger: this.logger,
90
- extra: Object.assign({ transport: provider.transport, name: config.name }, provider.enrichPublishedMesssageLog(config)),
91
- });
92
- throw new errors_js_1.SchemaValidationError(`Schema did not accept the published message: ${check.error.message}`);
93
- }
94
- const json = JSON.stringify(check.data);
95
- return { json, data: check.data };
96
- });
97
- const start = (0, message_logger_js_1.startTiming)();
98
- yield provider.publish(config, jsons.map((j) => j.json));
99
- const duration = (0, message_logger_js_1.getDuration)(start);
100
- jsons.forEach((msg) => {
101
- (0, message_logger_js_1.logMessage)({
102
- note: "Published message",
103
- message: msg.data,
104
- level: config.messageLogLevel,
105
- logger: this.logger,
106
- extra: Object.assign({ transport: provider.transport, name: config.name, durationMs: duration }, provider.enrichPublishedMesssageLog(config)),
107
- });
108
- });
109
- span.setTag("pubsub.duration_ms", duration);
110
- span.setTag("pubsub.message_count", message.length);
65
+ const provider = this.getProvider(config);
66
+ const { schema, schemaId } = this.assertSchema(config);
67
+ const jsons = messages.map((msg) => {
68
+ if (!msg.id) {
69
+ msg.id = (0, uuid_1.v4)();
111
70
  }
112
- catch (err) {
113
- span.setTag("error", err);
114
- throw err;
71
+ if (!msg.meta) {
72
+ msg.meta = {
73
+ createdAt: new Date().toISOString(),
74
+ publishedBy: "",
75
+ schemaId: schemaId,
76
+ };
77
+ }
78
+ else {
79
+ msg.meta.schemaId = schemaId;
80
+ }
81
+ const check = schema.safeEncode(msg);
82
+ if (!check.success) {
83
+ (0, message_logger_js_1.logMessage)({
84
+ note: "Publish message failed schema validation",
85
+ message: messages,
86
+ level: "error",
87
+ logger: this.logger,
88
+ extra: Object.assign({ transport: provider.transport, name: config.name }, provider.enrichPublishedMesssageLog(config)),
89
+ });
90
+ throw new errors_js_1.SchemaValidationError(`Schema did not accept the published message: ${check.error.message}`);
115
91
  }
116
- }));
92
+ const json = JSON.stringify(check.data);
93
+ return { json, data: check.data };
94
+ });
95
+ const start = (0, message_logger_js_1.startTiming)();
96
+ yield provider.publish(config, jsons.map((j) => j.json));
97
+ const duration = (0, message_logger_js_1.getDuration)(start);
98
+ jsons.forEach((msg) => {
99
+ (0, message_logger_js_1.logMessage)({
100
+ note: "Published message",
101
+ message: msg.data,
102
+ level: config.messageLogLevel,
103
+ logger: this.logger,
104
+ extra: Object.assign({ transport: provider.transport, name: config.name, durationMs: duration }, provider.enrichPublishedMesssageLog(config)),
105
+ });
106
+ });
107
+ span.setTag("pubsub.duration_ms", duration);
108
+ span.setTag("pubsub.message_count", messages.length);
117
109
  });
118
110
  }
119
111
  close() {
120
112
  return __awaiter(this, void 0, void 0, function* () {
121
- for (const provider of this.publisherProviders.values()) {
122
- yield provider.close();
123
- }
113
+ yield Promise.all(this.publisherProviders.values().map((provider) => provider.close()));
124
114
  });
125
115
  }
126
116
  getProvider(config) {
@@ -30,5 +30,6 @@ export declare class RabbitMqSubscriber implements SubscriberProvider {
30
30
  lastSent: Date | undefined;
31
31
  };
32
32
  private actuallySubscribe;
33
+ private consumeMessage;
33
34
  }
34
35
  export {};
@@ -15,6 +15,7 @@ const errors_js_1 = require("../errors.js");
15
15
  const config_js_1 = require("./config.js");
16
16
  const connection_js_1 = require("./connection.js");
17
17
  const create_log_error_payload_js_1 = require("../create-log-error-payload.js");
18
+ const dd_trace_wrapper_js_1 = require("../dd-trace.wrapper.js");
18
19
  class SubscribedMessage {
19
20
  constructor(owner, logger, config, onMessage, stop) {
20
21
  this.owner = owner;
@@ -115,73 +116,28 @@ class RabbitMqSubscriber {
115
116
  actuallySubscribe(channel, subscribedMessage) {
116
117
  return __awaiter(this, void 0, void 0, function* () {
117
118
  const retryDelay = subscribedMessage.config.retryDelay || 30000; // default 30 second retry delay
118
- const onRabbitMessage = (msg) => __awaiter(this, void 0, void 0, function* () {
119
- var _a, _b, _c, _d, _e, _f, _g, _h;
120
- const json = msg.content.toString("utf8");
121
- const retries = RabbitMqSubscriber.getRetries(msg);
122
- const sentDates = RabbitMqSubscriber.getSentDates(msg);
123
- const context = Object.assign(Object.assign({ retries }, sentDates), { exchangeName: msg.fields.exchange, routingKey: msg.fields.routingKey });
124
- let messageResult;
125
- try {
126
- messageResult = yield subscribedMessage.onMessage(json, context);
127
- }
128
- catch (err) {
129
- messageResult = interfaces_js_1.MessageResult.Retry;
130
- this.logger.error({
131
- message: `RabbitMq consumer unhandled exception, retrying message to ${retryExchangeName} ${msg.fields.routingKey}`,
132
- error: (0, create_log_error_payload_js_1.createLogErrorPayload)(err),
133
- });
134
- }
135
- if (messageResult === interfaces_js_1.MessageResult.Ok) {
136
- channel.ack(msg);
137
- return;
138
- }
139
- if (messageResult === interfaces_js_1.MessageResult.Retry &&
140
- subscribedMessage.config.retries &&
141
- retries >= subscribedMessage.config.retries) {
142
- messageResult = interfaces_js_1.MessageResult.Fail;
143
- }
144
- if (messageResult === interfaces_js_1.MessageResult.Fail) {
145
- (_b = (_a = this.logger).debug) === null || _b === void 0 ? void 0 : _b.call(_a, `RabbitMq retry count exceeded - sending message to DLQ`);
146
- channel.nack(msg, undefined, false);
147
- return;
148
- }
149
- const ok = yield ((_c = subscribedMessage.channel) === null || _c === void 0 ? void 0 : _c.publish(retryExchangeName, msg.fields.routingKey, msg.content, {
150
- contentType: msg.properties.contentType,
151
- expiration: retryDelay,
152
- timestamp: (_d = sentDates.firstSent) === null || _d === void 0 ? void 0 : _d.valueOf(),
153
- headers: {
154
- [RETRIES_HEADER]: retries + 1,
155
- [RETRYSENT_HEADER]: new Date().valueOf(),
156
- },
157
- }));
158
- if (ok) {
159
- (_f = (_e = this.logger).debug) === null || _f === void 0 ? void 0 : _f.call(_e, `RabbitMq retry queue success`);
160
- channel.ack(msg);
161
- }
162
- else {
163
- (_h = (_g = this.logger).debug) === null || _h === void 0 ? void 0 : _h.call(_g, `RabbitMq retry queue failure - nack-ing message instead`);
164
- channel.nack(msg, undefined, true);
165
- }
166
- });
167
119
  const config = subscribedMessage.config;
168
120
  const setupResult = yield this.connection.assertQueueAndBindings(channel, config);
169
121
  yield channel.prefetch(config.prefetch === undefined ? 5 : config.prefetch);
170
122
  const queueName = config.queueType === "dead-letter"
171
123
  ? setupResult.dlQueueName
172
124
  : setupResult.queueName;
173
- const retryExchangeName = setupResult.retryExchangeName;
174
- yield channel.consume(queueName, (m) => {
175
- if (m) {
176
- subscribedMessage.busy++;
177
- onRabbitMessage(m)
178
- .catch((err) => {
125
+ const onRabbitMessage = (msg) => __awaiter(this, void 0, void 0, function* () {
126
+ yield (0, dd_trace_wrapper_js_1.getTracer)().trace("pubsub.rabbit.consume", {
127
+ resource: `consume ${config.transport} ${queueName}`,
128
+ }, (span) => __awaiter(this, void 0, void 0, function* () {
129
+ try {
130
+ subscribedMessage.busy++;
131
+ yield this.consumeMessage(msg, channel, subscribedMessage, setupResult.retryExchangeName, retryDelay);
132
+ }
133
+ catch (err) {
179
134
  this.logger.error({
180
135
  message: "Unexpected error handling RabbitMq message",
181
136
  error: (0, create_log_error_payload_js_1.createLogErrorPayload)(err),
182
137
  });
138
+ span.setTag("error", err);
183
139
  try {
184
- channel.nack(m, undefined, true);
140
+ channel.nack(msg, undefined, true);
185
141
  }
186
142
  catch (err2) {
187
143
  this.logger.error({
@@ -189,10 +145,15 @@ class RabbitMqSubscriber {
189
145
  error: (0, create_log_error_payload_js_1.createLogErrorPayload)(err2),
190
146
  });
191
147
  }
192
- })
193
- .finally(() => {
148
+ }
149
+ finally {
194
150
  subscribedMessage.busy--;
195
- });
151
+ }
152
+ }));
153
+ });
154
+ yield channel.consume(queueName, (m) => {
155
+ if (m) {
156
+ void onRabbitMessage(m);
196
157
  }
197
158
  });
198
159
  channel.on("error", (err) => {
@@ -208,5 +169,56 @@ class RabbitMqSubscriber {
208
169
  });
209
170
  });
210
171
  }
172
+ consumeMessage(msg, channel, subscribedMessage, retryExchangeName, retryDelay) {
173
+ return __awaiter(this, void 0, void 0, function* () {
174
+ var _a, _b, _c, _d, _e, _f, _g, _h;
175
+ const json = msg.content.toString("utf8");
176
+ const retries = RabbitMqSubscriber.getRetries(msg);
177
+ const sentDates = RabbitMqSubscriber.getSentDates(msg);
178
+ const context = Object.assign(Object.assign({ retries }, sentDates), { exchangeName: msg.fields.exchange, routingKey: msg.fields.routingKey });
179
+ let messageResult;
180
+ try {
181
+ messageResult = yield subscribedMessage.onMessage(json, context);
182
+ }
183
+ catch (err) {
184
+ messageResult = interfaces_js_1.MessageResult.Retry;
185
+ this.logger.error({
186
+ message: `RabbitMq consumer unhandled exception, retrying message to ${retryExchangeName} ${msg.fields.routingKey}`,
187
+ error: (0, create_log_error_payload_js_1.createLogErrorPayload)(err),
188
+ });
189
+ }
190
+ if (messageResult === interfaces_js_1.MessageResult.Ok) {
191
+ channel.ack(msg);
192
+ return;
193
+ }
194
+ if (messageResult === interfaces_js_1.MessageResult.Retry &&
195
+ subscribedMessage.config.retries &&
196
+ retries >= subscribedMessage.config.retries) {
197
+ messageResult = interfaces_js_1.MessageResult.Fail;
198
+ }
199
+ if (messageResult === interfaces_js_1.MessageResult.Fail) {
200
+ (_b = (_a = this.logger).debug) === null || _b === void 0 ? void 0 : _b.call(_a, `RabbitMq retry count exceeded - sending message to DLQ`);
201
+ channel.nack(msg, undefined, false);
202
+ return;
203
+ }
204
+ const ok = yield ((_c = subscribedMessage.channel) === null || _c === void 0 ? void 0 : _c.publish(retryExchangeName, msg.fields.routingKey, msg.content, {
205
+ contentType: msg.properties.contentType,
206
+ expiration: retryDelay,
207
+ timestamp: (_d = sentDates.firstSent) === null || _d === void 0 ? void 0 : _d.valueOf(),
208
+ headers: {
209
+ [RETRIES_HEADER]: retries + 1,
210
+ [RETRYSENT_HEADER]: new Date().valueOf(),
211
+ },
212
+ }));
213
+ if (ok) {
214
+ (_f = (_e = this.logger).debug) === null || _f === void 0 ? void 0 : _f.call(_e, `RabbitMq retry queue success`);
215
+ channel.ack(msg);
216
+ }
217
+ else {
218
+ (_h = (_g = this.logger).debug) === null || _h === void 0 ? void 0 : _h.call(_g, `RabbitMq retry queue failure - nack-ing message instead`);
219
+ channel.nack(msg, undefined, true);
220
+ }
221
+ });
222
+ }
211
223
  }
212
224
  exports.RabbitMqSubscriber = RabbitMqSubscriber;
@@ -15,7 +15,6 @@ const errors_js_1 = require("./errors.js");
15
15
  const events_1 = require("events");
16
16
  const message_logger_js_1 = require("./message-logger.js");
17
17
  const create_log_error_payload_js_1 = require("./create-log-error-payload.js");
18
- const dd_trace_wrapper_js_1 = require("./dd-trace.wrapper.js");
19
18
  class SubscribedMessage {
20
19
  constructor(stop) {
21
20
  this.stop = stop;
@@ -57,79 +56,69 @@ class Subscriber {
57
56
  throw new errors_js_1.MissingPubSubProviderError(`No provider configured for ${config.transport}`);
58
57
  }
59
58
  const transform = (jsonStr, context) => __awaiter(this, void 0, void 0, function* () {
60
- return yield (0, dd_trace_wrapper_js_1.getTracer)().trace("pubsub.handleMessage", {
61
- resource: config.name,
62
- tags: {
63
- "pubsub.transport": config.transport,
64
- },
65
- }, (span) => __awaiter(this, void 0, void 0, function* () {
66
- const start = (0, message_logger_js_1.startTiming)();
67
- const jsonObject = JSON.parse(jsonStr);
68
- const r = schema.safeDecode(jsonObject);
69
- if (!r.success) {
70
- const durationMs = (0, message_logger_js_1.getDuration)(start);
71
- (0, message_logger_js_1.logMessage)({
72
- note: "Subscribed message failed schema validation",
73
- message: jsonObject,
74
- level: "error",
75
- logger: this.logger,
76
- extra: Object.assign({ transport: provider.transport, name: config.name, durationMs }, provider.enrichHandledMesssageLog(config)),
77
- });
78
- const handledEventContext = {
79
- message: jsonStr,
80
- context,
81
- config,
82
- durationMs,
83
- result: interfaces_js_1.MessageResult.Fail,
84
- };
85
- this.events.emit("schemaError", handledEventContext);
86
- this.events.emit("messageHandled", handledEventContext);
87
- span.setTag("error", r.error);
88
- return interfaces_js_1.MessageResult.Fail;
89
- }
90
- try {
91
- const result = yield onMessage(r.data, context);
92
- const durationMs = (0, message_logger_js_1.getDuration)(start);
93
- const eventContext = {
94
- message: jsonStr,
95
- context,
96
- config,
97
- durationMs,
98
- result,
99
- };
100
- (0, message_logger_js_1.logMessage)({
101
- note: "Subscriber processed message",
102
- message: r.data,
103
- level: config.messageLogLevel,
104
- logger: this.logger,
105
- extra: Object.assign({ transport: provider.transport, name: config.name, durationMs,
106
- result }, provider.enrichHandledMesssageLog(config)),
107
- });
108
- this.events.emit("messageHandled", eventContext);
109
- span.setTag("pubsub.duration_ms", durationMs);
110
- return result;
111
- }
112
- catch (err) {
113
- const durationMs = (0, message_logger_js_1.getDuration)(start);
114
- (0, message_logger_js_1.logMessage)({
115
- note: "Subscriber error when processing message",
116
- message: r.data,
117
- level: "error",
118
- logger: this.logger,
119
- extra: Object.assign(Object.assign({ transport: provider.transport, name: config.name, durationMs }, provider.enrichHandledMesssageLog(config)), { error: (0, create_log_error_payload_js_1.createLogErrorPayload)(err) }),
120
- });
121
- const eventContext = {
122
- message: jsonStr,
123
- context,
124
- config,
125
- durationMs,
126
- err,
127
- };
128
- this.events.emit("messageHandled", eventContext);
129
- span.setTag("error", r.error);
130
- throw err;
131
- }
132
- }));
59
+ const start = (0, message_logger_js_1.startTiming)();
60
+ const jsonObject = JSON.parse(jsonStr);
61
+ const r = schema.safeDecode(jsonObject);
62
+ if (!r.success) {
63
+ const durationMs = (0, message_logger_js_1.getDuration)(start);
64
+ (0, message_logger_js_1.logMessage)({
65
+ note: "Subscribed message failed schema validation",
66
+ message: jsonObject,
67
+ level: "error",
68
+ logger: this.logger,
69
+ extra: Object.assign({ transport: provider.transport, name: config.name, durationMs }, provider.enrichHandledMesssageLog(config)),
70
+ });
71
+ const handledEventContext = {
72
+ message: jsonStr,
73
+ context,
74
+ config,
75
+ durationMs,
76
+ result: interfaces_js_1.MessageResult.Fail,
77
+ };
78
+ this.events.emit("schemaError", handledEventContext);
79
+ this.events.emit("messageHandled", handledEventContext);
80
+ return interfaces_js_1.MessageResult.Fail;
81
+ }
82
+ try {
83
+ const result = yield onMessage(r.data, context);
84
+ const durationMs = (0, message_logger_js_1.getDuration)(start);
85
+ const eventContext = {
86
+ message: jsonStr,
87
+ context,
88
+ config,
89
+ durationMs,
90
+ result,
91
+ };
92
+ (0, message_logger_js_1.logMessage)({
93
+ note: "Subscriber processed message",
94
+ message: r.data,
95
+ level: config.messageLogLevel,
96
+ logger: this.logger,
97
+ extra: Object.assign({ transport: provider.transport, name: config.name, durationMs,
98
+ result }, provider.enrichHandledMesssageLog(config)),
99
+ });
100
+ this.events.emit("messageHandled", eventContext);
101
+ return result;
102
+ }
103
+ catch (err) {
104
+ const durationMs = (0, message_logger_js_1.getDuration)(start);
105
+ (0, message_logger_js_1.logMessage)({
106
+ note: "Subscriber error when processing message",
107
+ message: r.data,
108
+ level: "error",
109
+ logger: this.logger,
110
+ extra: Object.assign(Object.assign({ transport: provider.transport, name: config.name, durationMs }, provider.enrichHandledMesssageLog(config)), { error: (0, create_log_error_payload_js_1.createLogErrorPayload)(err) }),
111
+ });
112
+ const eventContext = {
113
+ message: jsonStr,
114
+ context,
115
+ config,
116
+ durationMs,
117
+ err,
118
+ };
119
+ this.events.emit("messageHandled", eventContext);
120
+ throw err;
121
+ }
133
122
  });
134
123
  this.logger.log(`Starting subscriber for ${config.transport}:${config.name}`);
135
124
  subscribedMessage = new SubscribedMessage(yield provider.startSubscribe(config, transform));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@palmetto/pubsub",
3
- "version": "2.2.3",
3
+ "version": "2.2.5",
4
4
  "main": "./dist/main.js",
5
5
  "scripts": {
6
6
  "lint": "yarn run -T eslint --fix ./src",