@cryptexlabs/codex-nodejs-common 0.2.3 → 0.3.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/lib/package.json +2 -2
- package/lib/src/auth/index.js +5 -1
- package/lib/src/auth/index.js.map +1 -1
- package/lib/src/client/index.js +5 -1
- package/lib/src/client/index.js.map +1 -1
- package/lib/src/config/default-config.js +5 -5
- package/lib/src/config/default-config.js.map +1 -1
- package/lib/src/config/index.js +5 -1
- package/lib/src/config/index.js.map +1 -1
- package/lib/src/config/kafka-config.d.ts +2 -1
- package/lib/src/config/kafka-config.interface.d.ts +1 -0
- package/lib/src/config/kafka-config.js +2 -1
- package/lib/src/config/kafka-config.js.map +1 -1
- package/lib/src/context/context.builder.js +2 -2
- package/lib/src/context/context.builder.js.map +1 -1
- package/lib/src/context/index.js +5 -1
- package/lib/src/context/index.js.map +1 -1
- package/lib/src/decorator/api-meta-headers.js +12 -12
- package/lib/src/decorator/api-meta-headers.js.map +1 -1
- package/lib/src/decorator/api-pagination.js +3 -3
- package/lib/src/decorator/api-pagination.js.map +1 -1
- package/lib/src/decorator/index.js +5 -1
- package/lib/src/decorator/index.js.map +1 -1
- package/lib/src/event/event-handler.d.ts +1 -1
- package/lib/src/event/event-handler.js +4 -1
- package/lib/src/event/event-handler.js.map +1 -1
- package/lib/src/event/index.js +5 -1
- package/lib/src/event/index.js.map +1 -1
- package/lib/src/event/websocket-event.handler.js +2 -2
- package/lib/src/event/websocket-event.handler.js.map +1 -1
- package/lib/src/exception/index.js +5 -1
- package/lib/src/exception/index.js.map +1 -1
- package/lib/src/filter/app-http-exception-filter.js +2 -2
- package/lib/src/filter/app-http-exception-filter.js.map +1 -1
- package/lib/src/filter/http-status.interceptor.js +2 -2
- package/lib/src/filter/http-status.interceptor.js.map +1 -1
- package/lib/src/filter/index.js +5 -1
- package/lib/src/filter/index.js.map +1 -1
- package/lib/src/index.js +5 -1
- package/lib/src/index.js.map +1 -1
- package/lib/src/logger/context.logger.js +1 -1
- package/lib/src/logger/context.logger.js.map +1 -1
- package/lib/src/logger/custom.logger.js +1 -1
- package/lib/src/logger/custom.logger.js.map +1 -1
- package/lib/src/logger/index.js +5 -1
- package/lib/src/logger/index.js.map +1 -1
- package/lib/src/message/index.js +5 -1
- package/lib/src/message/index.js.map +1 -1
- package/lib/src/message/message-meta.js +1 -1
- package/lib/src/message/message-meta.js.map +1 -1
- package/lib/src/pipe/country-code.pipe.js +1 -1
- package/lib/src/pipe/country-code.pipe.js.map +1 -1
- package/lib/src/pipe/csv.pipe.js +1 -1
- package/lib/src/pipe/csv.pipe.js.map +1 -1
- package/lib/src/pipe/index.d.ts +2 -0
- package/lib/src/pipe/index.js +7 -1
- package/lib/src/pipe/index.js.map +1 -1
- package/lib/src/pipe/joi-http-validation.pipe.js +1 -1
- package/lib/src/pipe/joi-http-validation.pipe.js.map +1 -1
- package/lib/src/pipe/language-code.pipe.js +1 -1
- package/lib/src/pipe/language-code.pipe.js.map +1 -1
- package/lib/src/pipe/not-empty.pipe.js +1 -1
- package/lib/src/pipe/not-empty.pipe.js.map +1 -1
- package/lib/src/pipe/uuidv4.array.validation.pipe.js +1 -1
- package/lib/src/pipe/uuidv4.array.validation.pipe.js.map +1 -1
- package/lib/src/pipe/uuidv4.validation.pipe.d.ts +6 -0
- package/lib/src/pipe/uuidv4.validation.pipe.js +32 -0
- package/lib/src/pipe/uuidv4.validation.pipe.js.map +1 -0
- package/lib/src/response/healthz-response.js +1 -1
- package/lib/src/response/healthz-response.js.map +1 -1
- package/lib/src/response/index.js +5 -1
- package/lib/src/response/index.js.map +1 -1
- package/lib/src/result/index.js +5 -1
- package/lib/src/result/index.js.map +1 -1
- package/lib/src/service/consumer/consumer-service-delegate.interface.d.ts +2 -0
- package/lib/src/service/consumer/consumer.service.d.ts +1 -0
- package/lib/src/service/consumer/consumer.service.js +23 -10
- package/lib/src/service/consumer/consumer.service.js.map +1 -1
- package/lib/src/service/consumer/index.js +5 -1
- package/lib/src/service/consumer/index.js.map +1 -1
- package/lib/src/service/consumer/websocket-consumer.service.js +5 -5
- package/lib/src/service/consumer/websocket-consumer.service.js.map +1 -1
- package/lib/src/service/elasticsearch/elasticsearch-healthz.service.js +5 -5
- package/lib/src/service/elasticsearch/elasticsearch-healthz.service.js.map +1 -1
- package/lib/src/service/elasticsearch/index.js +5 -1
- package/lib/src/service/elasticsearch/index.js.map +1 -1
- package/lib/src/service/healthz/healthz.service.js +3 -3
- package/lib/src/service/healthz/healthz.service.js.map +1 -1
- package/lib/src/service/healthz/index.js +5 -1
- package/lib/src/service/healthz/index.js.map +1 -1
- package/lib/src/service/index.js +5 -1
- package/lib/src/service/index.js.map +1 -1
- package/lib/src/service/kafka/index.d.ts +1 -0
- package/lib/src/service/kafka/index.js +6 -1
- package/lib/src/service/kafka/index.js.map +1 -1
- package/lib/src/service/kafka/kafka.replay.messages.d.ts +10 -0
- package/lib/src/service/kafka/kafka.replay.messages.js +42 -0
- package/lib/src/service/kafka/kafka.replay.messages.js.map +1 -0
- package/lib/src/service/kafka/kafka.service.d.ts +2 -0
- package/lib/src/service/kafka/kafka.service.js +83 -3
- package/lib/src/service/kafka/kafka.service.js.map +1 -1
- package/lib/src/service/kafka/kafka.stub.service.js +1 -1
- package/lib/src/service/kafka/kafka.stub.service.js.map +1 -1
- package/lib/src/service/socket/index.js +5 -1
- package/lib/src/service/socket/index.js.map +1 -1
- package/lib/src/service/socket/websocket.gateway.js +8 -8
- package/lib/src/service/socket/websocket.gateway.js.map +1 -1
- package/lib/src/util/index.js +5 -1
- package/lib/src/util/index.js.map +1 -1
- package/package.json +2 -2
- package/src/config/default-config.ts +2 -1
- package/src/config/kafka-config.interface.ts +1 -0
- package/src/config/kafka-config.ts +4 -1
- package/src/event/event-handler.ts +5 -2
- package/src/pipe/index.ts +2 -0
- package/src/pipe/uuidv4.validation.pipe.ts +23 -0
- package/src/service/consumer/consumer-service-delegate.interface.ts +2 -0
- package/src/service/consumer/consumer.service.ts +26 -3
- package/src/service/kafka/index.ts +1 -0
- package/src/service/kafka/kafka.replay.messages.ts +33 -0
- package/src/service/kafka/kafka.service.ts +145 -0
|
@@ -2,6 +2,7 @@ import { Inject, Injectable, LoggerService } from "@nestjs/common";
|
|
|
2
2
|
import {
|
|
3
3
|
Admin,
|
|
4
4
|
Consumer,
|
|
5
|
+
EachMessagePayload,
|
|
5
6
|
ITopicConfig,
|
|
6
7
|
Kafka,
|
|
7
8
|
Message,
|
|
@@ -115,6 +116,39 @@ export class KafkaService implements ConsumerServiceDelegateInterface {
|
|
|
115
116
|
});
|
|
116
117
|
}
|
|
117
118
|
|
|
119
|
+
public async startManualConsumer(
|
|
120
|
+
topics: (string | RegExp)[],
|
|
121
|
+
callback: (topic: string, message: Message) => Promise<void>
|
|
122
|
+
): Promise<void> {
|
|
123
|
+
await this._setManualConsume();
|
|
124
|
+
|
|
125
|
+
const promises = [];
|
|
126
|
+
for (const topic of topics) {
|
|
127
|
+
promises.push(
|
|
128
|
+
this._kafkaConsumer.subscribe({ topic, fromBeginning: true })
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
await Promise.all(promises);
|
|
133
|
+
|
|
134
|
+
await this._ensureTopicsExist(topics);
|
|
135
|
+
|
|
136
|
+
const results = [
|
|
137
|
+
new Promise((resolve) => {
|
|
138
|
+
this._kafkaConsumer.run({
|
|
139
|
+
eachMessage: async (messagePayload: EachMessagePayload) => {
|
|
140
|
+
const { topic, partition, message } = messagePayload;
|
|
141
|
+
await callback(topic, message);
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
}),
|
|
145
|
+
];
|
|
146
|
+
await Promise.all(results);
|
|
147
|
+
} catch (e) {
|
|
148
|
+
this.logger.error(e.message, e.trace);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
118
152
|
private async _ensureTopicsExist(topics: (string | RegExp)[]): Promise<void> {
|
|
119
153
|
const stringTopics = [];
|
|
120
154
|
for (const topic of topics) {
|
|
@@ -165,4 +199,115 @@ export class KafkaService implements ConsumerServiceDelegateInterface {
|
|
|
165
199
|
messages,
|
|
166
200
|
});
|
|
167
201
|
}
|
|
202
|
+
|
|
203
|
+
private async _setManualConsume(): Promise<void> {
|
|
204
|
+
/* Based on solution provided here:
|
|
205
|
+
* https://github.com/tulios/kafkajs/issues/825#issuecomment-674106799
|
|
206
|
+
*
|
|
207
|
+
* 1. We need to know which partitions we are assigned.
|
|
208
|
+
* 2. Which partitions have we consumed the last offset for
|
|
209
|
+
* 3. If all partitions have 0 lag, we exit.
|
|
210
|
+
*/
|
|
211
|
+
|
|
212
|
+
/*
|
|
213
|
+
* `consumedTopicPartitions` will be an object of all topic-partitions
|
|
214
|
+
* and a boolean indicating whether or not we have consumed all
|
|
215
|
+
* messages in that topic-partition. For example:
|
|
216
|
+
*
|
|
217
|
+
* {
|
|
218
|
+
* "topic-test-0": false,
|
|
219
|
+
* "topic-test-1": false,
|
|
220
|
+
* "topic-test-2": false
|
|
221
|
+
* }
|
|
222
|
+
*/
|
|
223
|
+
let consumedTopicPartitions = {};
|
|
224
|
+
this._kafkaConsumer.on(
|
|
225
|
+
this._kafkaConsumer.events.GROUP_JOIN,
|
|
226
|
+
async ({ payload }) => {
|
|
227
|
+
const { memberAssignment } = payload;
|
|
228
|
+
|
|
229
|
+
consumedTopicPartitions = Object.entries(memberAssignment).reduce(
|
|
230
|
+
(topics, [topic, partitions]) => {
|
|
231
|
+
for (const partition in partitions) {
|
|
232
|
+
this.logger.debug("topic-partition: ", `${topic}-${partition}`);
|
|
233
|
+
topics[`${topic}-${partition}`] = false;
|
|
234
|
+
}
|
|
235
|
+
return topics;
|
|
236
|
+
},
|
|
237
|
+
{}
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
/*
|
|
243
|
+
* This is extremely unergonomic, but if we are currently caught up to the head
|
|
244
|
+
* of all topic-partitions, we won't actually get any batches, which means we'll
|
|
245
|
+
* never find out that we are actually caught up. So as a workaround, what we can do
|
|
246
|
+
* is to check in `FETCH_START` if we have previously made a fetch without
|
|
247
|
+
* processing any batches in between. If so, it means that we received empty
|
|
248
|
+
* fetch responses, meaning there was no more data to fetch.
|
|
249
|
+
*
|
|
250
|
+
* We need to initially set this to true, or we would immediately exit.
|
|
251
|
+
*/
|
|
252
|
+
let processedBatch = true;
|
|
253
|
+
this._kafkaConsumer.on(this._kafkaConsumer.events.FETCH_START, async () => {
|
|
254
|
+
if (processedBatch === false) {
|
|
255
|
+
await this._kafkaConsumer.disconnect();
|
|
256
|
+
process.exit(0);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
processedBatch = false;
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
/*
|
|
263
|
+
* Now whenever we have finished processing a batch, we'll update `consumedTopicPartitions`
|
|
264
|
+
* and exit if all topic-partitions have been consumed,
|
|
265
|
+
*/
|
|
266
|
+
this._kafkaConsumer.on(
|
|
267
|
+
this._kafkaConsumer.events.END_BATCH_PROCESS,
|
|
268
|
+
async ({ payload }) => {
|
|
269
|
+
const { topic, partition, offsetLag } = payload;
|
|
270
|
+
|
|
271
|
+
consumedTopicPartitions[`${topic}-${partition}`] = offsetLag === "0";
|
|
272
|
+
|
|
273
|
+
if (
|
|
274
|
+
Object.values(consumedTopicPartitions).every((consumed) =>
|
|
275
|
+
Boolean(consumed)
|
|
276
|
+
)
|
|
277
|
+
) {
|
|
278
|
+
await this._kafkaConsumer.disconnect();
|
|
279
|
+
process.exit(0);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
processedBatch = true;
|
|
283
|
+
}
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
// Graceful shutdown
|
|
287
|
+
const errorTypes = ["unhandledRejection", "uncaughtException"];
|
|
288
|
+
const signalTraps: NodeJS.Signals[] = ["SIGTERM", "SIGINT", "SIGUSR2"];
|
|
289
|
+
|
|
290
|
+
errorTypes.map((type) => {
|
|
291
|
+
process.on(type, async (e) => {
|
|
292
|
+
try {
|
|
293
|
+
this.logger.debug(`process.on ${type}`);
|
|
294
|
+
this.logger.error(e);
|
|
295
|
+
await this.disconnect();
|
|
296
|
+
process.exit(0);
|
|
297
|
+
} catch (_) {
|
|
298
|
+
process.exit(1);
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
signalTraps.map((type) => {
|
|
304
|
+
process.once(type, async () => {
|
|
305
|
+
try {
|
|
306
|
+
await this.disconnect();
|
|
307
|
+
} finally {
|
|
308
|
+
process.kill(process.pid, type);
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
}
|
|
168
313
|
}
|