@aichatwar/shared 1.0.101 → 1.0.103
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/build/events/kafka/baseListener.d.ts +2 -0
- package/build/events/kafka/baseListener.js +66 -26
- package/build/events/messageIngestEvents.d.ts +11 -0
- package/build/events/messageIngestEvents.js +2 -0
- package/build/events/presenceEvents.d.ts +10 -0
- package/build/events/presenceEvents.js +2 -0
- package/build/events/subjects.d.ts +3 -1
- package/build/events/subjects.js +2 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +2 -0
- package/package.json +1 -1
|
@@ -7,6 +7,8 @@ export declare abstract class Listener<T extends BaseEvent> {
|
|
|
7
7
|
protected consumer: Consumer;
|
|
8
8
|
protected ackDeadline: number;
|
|
9
9
|
private currentPayload?;
|
|
10
|
+
private retryCount;
|
|
11
|
+
private readonly maxRetries;
|
|
10
12
|
constructor(consumer: Consumer);
|
|
11
13
|
ack(): Promise<void>;
|
|
12
14
|
listen(): Promise<void>;
|
|
@@ -13,6 +13,8 @@ exports.Listener = void 0;
|
|
|
13
13
|
class Listener {
|
|
14
14
|
constructor(consumer) {
|
|
15
15
|
this.ackDeadline = 5 * 1000; // 5 seconds
|
|
16
|
+
this.retryCount = 0;
|
|
17
|
+
this.maxRetries = 5;
|
|
16
18
|
this.consumer = consumer;
|
|
17
19
|
}
|
|
18
20
|
// Manual acknowledgment method
|
|
@@ -31,36 +33,74 @@ class Listener {
|
|
|
31
33
|
}
|
|
32
34
|
listen() {
|
|
33
35
|
return __awaiter(this, void 0, void 0, function* () {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
var _a;
|
|
37
|
+
try {
|
|
38
|
+
yield this.consumer.connect();
|
|
39
|
+
// Handle consumer errors (including partition errors)
|
|
40
|
+
this.consumer.on('consumer.crash', (event) => {
|
|
41
|
+
var _a;
|
|
42
|
+
const error = event.payload.error;
|
|
43
|
+
if ((_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.includes('does not host this topic-partition')) {
|
|
44
|
+
console.warn(`[${this.topic}] Consumer partition error (non-fatal):`, error.message);
|
|
45
|
+
// Don't crash - this is often a transient error
|
|
43
46
|
return;
|
|
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
47
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
console.error(`[${this.topic}] Consumer crashed:`, error);
|
|
49
|
+
});
|
|
50
|
+
yield this.consumer.subscribe({
|
|
51
|
+
topic: this.topic,
|
|
52
|
+
fromBeginning: false,
|
|
53
|
+
});
|
|
54
|
+
// Reset retry count on successful connection
|
|
55
|
+
this.retryCount = 0;
|
|
56
|
+
console.log(`Listening to topic: ${this.topic} with groupId: ${this.groupId}`);
|
|
57
|
+
yield this.consumer.run({
|
|
58
|
+
eachMessage: (payload) => __awaiter(this, void 0, void 0, function* () {
|
|
59
|
+
if (!payload.message.value)
|
|
60
|
+
return;
|
|
61
|
+
console.log(`Message received -> topic: ${this.topic}, groupId: ${this.groupId}`);
|
|
62
|
+
// Store current payload for manual ack
|
|
63
|
+
this.currentPayload = payload;
|
|
64
|
+
try {
|
|
65
|
+
const data = JSON.parse(payload.message.value.toString());
|
|
66
|
+
yield this.onMessage(data, payload);
|
|
67
|
+
// Note: Child listeners must call this.ack() manually after successful processing
|
|
68
|
+
// If they don't call ack(), the message will be redelivered
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
console.error(`Error processing message for topic: ${this.topic}`, error);
|
|
72
|
+
// In case of error, we don't commit the offset, so the message will be redelivered
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
// Clear the current payload
|
|
77
|
+
this.currentPayload = undefined;
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
// Handle connection/subscription errors gracefully
|
|
84
|
+
// The "This server does not host this topic-partition" error is often harmless
|
|
85
|
+
// and occurs when KafkaJS tries to list offsets for a topic that doesn't exist yet or has no messages
|
|
86
|
+
if ((_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.includes('does not host this topic-partition')) {
|
|
87
|
+
this.retryCount++;
|
|
88
|
+
if (this.retryCount <= this.maxRetries) {
|
|
89
|
+
console.warn(`Topic partition error for ${this.topic} (attempt ${this.retryCount}/${this.maxRetries}):`, error.message);
|
|
90
|
+
// Retry subscription after a delay (exponential backoff)
|
|
91
|
+
const delay = Math.min(5000 * Math.pow(2, this.retryCount - 1), 30000);
|
|
92
|
+
setTimeout(() => this.listen(), delay);
|
|
93
|
+
return;
|
|
57
94
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
95
|
+
else {
|
|
96
|
+
console.error(`Max retries reached for topic ${this.topic}. Error:`, error.message);
|
|
97
|
+
// Don't throw - just log and continue (service will still work for other topics)
|
|
98
|
+
return;
|
|
61
99
|
}
|
|
62
|
-
}
|
|
63
|
-
|
|
100
|
+
}
|
|
101
|
+
console.error(`Error setting up listener for topic: ${this.topic}`, error);
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
64
104
|
});
|
|
65
105
|
}
|
|
66
106
|
}
|
|
@@ -31,5 +31,7 @@ export declare enum Subjects {
|
|
|
31
31
|
MessageCreated = "message.created",
|
|
32
32
|
MessageUpdated = "message.updated",
|
|
33
33
|
MessageRead = "message.read",
|
|
34
|
-
MessageDeleted = "message.deleted"
|
|
34
|
+
MessageDeleted = "message.deleted",
|
|
35
|
+
MessageIngest = "message.ingest",
|
|
36
|
+
PresenceUpdated = "presence.updated"
|
|
35
37
|
}
|
package/build/events/subjects.js
CHANGED
|
@@ -36,4 +36,6 @@ var Subjects;
|
|
|
36
36
|
Subjects["MessageUpdated"] = "message.updated";
|
|
37
37
|
Subjects["MessageRead"] = "message.read";
|
|
38
38
|
Subjects["MessageDeleted"] = "message.deleted";
|
|
39
|
+
Subjects["MessageIngest"] = "message.ingest";
|
|
40
|
+
Subjects["PresenceUpdated"] = "presence.updated";
|
|
39
41
|
})(Subjects || (exports.Subjects = Subjects = {}));
|
package/build/index.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ export * from "./events/agentEvents";
|
|
|
21
21
|
export * from "./events/commentEvents";
|
|
22
22
|
export * from "./events/roomEvents";
|
|
23
23
|
export * from "./events/messageEvents";
|
|
24
|
+
export * from "./events/messageIngestEvents";
|
|
25
|
+
export * from "./events/presenceEvents";
|
|
24
26
|
export * from "./events/types/orderStatus";
|
|
25
27
|
export * from "./events/types/friendshipStatus";
|
|
26
28
|
export * from "./events/types/userStatus";
|
package/build/index.js
CHANGED
|
@@ -37,6 +37,8 @@ __exportStar(require("./events/agentEvents"), exports);
|
|
|
37
37
|
__exportStar(require("./events/commentEvents"), exports);
|
|
38
38
|
__exportStar(require("./events/roomEvents"), exports);
|
|
39
39
|
__exportStar(require("./events/messageEvents"), exports);
|
|
40
|
+
__exportStar(require("./events/messageIngestEvents"), exports);
|
|
41
|
+
__exportStar(require("./events/presenceEvents"), exports);
|
|
40
42
|
__exportStar(require("./events/types/orderStatus"), exports);
|
|
41
43
|
__exportStar(require("./events/types/friendshipStatus"), exports);
|
|
42
44
|
__exportStar(require("./events/types/userStatus"), exports);
|