@aichatwar/shared 1.0.90 → 1.0.94

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.
@@ -5,6 +5,9 @@ export declare abstract class Listener<T extends BaseEvent> {
5
5
  abstract groupId: string;
6
6
  abstract onMessage(data: T['data'], payload: EachMessagePayload): Promise<void>;
7
7
  protected consumer: Consumer;
8
+ protected ackDeadline: number;
9
+ private currentPayload?;
8
10
  constructor(consumer: Consumer);
11
+ protected ack(): Promise<void>;
9
12
  listen(): Promise<void>;
10
13
  }
@@ -10,25 +10,55 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.Listener = void 0;
13
- // Updated event to base
14
13
  class Listener {
15
14
  constructor(consumer) {
15
+ this.ackDeadline = 5 * 1000; // 5 seconds
16
16
  this.consumer = consumer;
17
17
  }
18
+ // Manual acknowledgment method
19
+ ack() {
20
+ return __awaiter(this, void 0, void 0, function* () {
21
+ if (!this.currentPayload) {
22
+ throw new Error('No current payload to acknowledge');
23
+ }
24
+ yield this.consumer.commitOffsets([{
25
+ topic: this.currentPayload.topic,
26
+ partition: this.currentPayload.partition,
27
+ offset: (BigInt(this.currentPayload.message.offset) + BigInt(1)).toString()
28
+ }]);
29
+ console.log(`Message manually acknowledged for topic: ${this.topic}`);
30
+ });
31
+ }
18
32
  listen() {
19
33
  return __awaiter(this, void 0, void 0, function* () {
20
- yield this.consumer.connect(); // ✅ connect once
34
+ yield this.consumer.connect();
21
35
  yield this.consumer.subscribe({
22
36
  topic: this.topic,
23
37
  fromBeginning: false,
24
38
  });
25
- console.log(`👂 Listening to topic: ${this.topic}`);
39
+ console.log(`Listening to topic: ${this.topic} with groupId: ${this.groupId}`);
26
40
  yield this.consumer.run({
27
41
  eachMessage: (payload) => __awaiter(this, void 0, void 0, function* () {
28
42
  if (!payload.message.value)
29
43
  return;
30
- const data = JSON.parse(payload.message.value.toString());
31
- yield this.onMessage(data, payload);
44
+ console.log(`Message received -> topic: ${this.topic}, groupId: ${this.groupId}`);
45
+ // Store current payload for manual ack
46
+ this.currentPayload = payload;
47
+ try {
48
+ const data = JSON.parse(payload.message.value.toString());
49
+ yield this.onMessage(data, payload);
50
+ // Note: Child listeners must call this.ack() manually after successful processing
51
+ // If they don't call ack(), the message will be redelivered
52
+ }
53
+ catch (error) {
54
+ console.error(`Error processing message for topic: ${this.topic}`, error);
55
+ // In case of error, we don't commit the offset, so the message will be redelivered
56
+ throw error;
57
+ }
58
+ finally {
59
+ // Clear the current payload
60
+ this.currentPayload = undefined;
61
+ }
32
62
  })
33
63
  });
34
64
  });
@@ -3,6 +3,8 @@ import { BaseEvent } from '../baseEvent';
3
3
  export declare abstract class Publisher<T extends BaseEvent> {
4
4
  abstract topic: T['subject'];
5
5
  protected producer: Producer;
6
+ protected maxRetries: number;
7
+ protected retryDelay: number;
6
8
  constructor(producer: Producer);
7
9
  publish(data: T['data']): Promise<void>;
8
10
  }
@@ -12,22 +12,41 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.Publisher = void 0;
13
13
  class Publisher {
14
14
  constructor(producer) {
15
+ this.maxRetries = 3;
16
+ this.retryDelay = 1000; // 1 second
15
17
  this.producer = producer;
16
18
  }
17
19
  publish(data) {
18
20
  return __awaiter(this, void 0, void 0, function* () {
19
21
  if (!this.producer)
20
22
  throw new Error('Producer not defined');
21
- try {
22
- yield this.producer.send({
23
- topic: this.topic,
24
- messages: [{ value: JSON.stringify(data) }],
25
- });
26
- }
27
- catch (err) {
28
- console.error(`❌ Publish failed on first try for ${this.topic}`, err);
29
- throw err;
23
+ let lastError = null;
24
+ for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
25
+ try {
26
+ yield this.producer.send({
27
+ topic: this.topic,
28
+ messages: [{
29
+ value: JSON.stringify(data),
30
+ key: data.id || undefined, // Use id as key for partitioning if available
31
+ timestamp: Date.now().toString()
32
+ }],
33
+ });
34
+ console.log(`Event published successfully: ${this.topic}`, data);
35
+ return; // Success, exit retry loop
36
+ }
37
+ catch (err) {
38
+ lastError = err;
39
+ console.error(`❌ Publish attempt ${attempt}/${this.maxRetries} failed for ${this.topic}`, err);
40
+ if (attempt < this.maxRetries) {
41
+ console.log(`Retrying in ${this.retryDelay}ms...`);
42
+ yield new Promise(resolve => setTimeout(resolve, this.retryDelay));
43
+ this.retryDelay *= 2; // Exponential backoff
44
+ }
45
+ }
30
46
  }
47
+ // All retries failed
48
+ console.error(`❌ Publish failed after ${this.maxRetries} attempts for ${this.topic}`);
49
+ throw lastError || new Error(`Failed to publish to ${this.topic} after ${this.maxRetries} attempts`);
31
50
  });
32
51
  }
33
52
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aichatwar/shared",
3
- "version": "1.0.90",
3
+ "version": "1.0.94",
4
4
  "main": "./build/index.js",
5
5
  "typs": "./build/index.d.ts",
6
6
  "files": [