wsp-ms-core 1.1.29 → 1.1.30
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/dist/index.cjs +57 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +57 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1803,18 +1803,44 @@ var KafkaManager = class extends EventManager {
|
|
|
1803
1803
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1804
1804
|
this.runtimeProcess = globalThis?.process;
|
|
1805
1805
|
this.producerConnected = false;
|
|
1806
|
+
this.producerConnectPromise = null;
|
|
1806
1807
|
this.isRecoveringLeader = false;
|
|
1807
1808
|
this.seedBrokers = this.resolveBrokerList(this._connection.brokers ?? []);
|
|
1808
|
-
|
|
1809
|
+
const envGroupId = this.runtimeProcess?.env?.KAFKA_GROUP;
|
|
1810
|
+
this.hasExplicitGroupId = Boolean(envGroupId);
|
|
1811
|
+
this.groupId = envGroupId || "__missing-kafka-group__";
|
|
1812
|
+
if (!this.hasExplicitGroupId) {
|
|
1813
|
+
console.warn("[KafkaManager] KAFKA_GROUP is not set. Producing is allowed, but consuming will fail until a unique group id is configured.");
|
|
1814
|
+
}
|
|
1809
1815
|
this.initializeKafkaClients(this.seedBrokers);
|
|
1810
1816
|
this.leaderSelectionPromise = this.pinToLeaderBroker();
|
|
1811
1817
|
}
|
|
1818
|
+
// La conexión se comparte entre sends concurrentes vía un latch: sin él, dos send() en paralelo
|
|
1819
|
+
// dispararían dos connect() simultáneos sobre el mismo producer. El producer queda conectado
|
|
1820
|
+
// entre sends (kafkajs está diseñado para conexiones long-lived); solo stop() lo desconecta.
|
|
1821
|
+
// Los guards `this.producer === producer` protegen contra initializeKafkaClients() reemplazando
|
|
1822
|
+
// el producer a mitad de un connect (recovery de líder): sin ellos, el latch viejo marcaría como
|
|
1823
|
+
// conectado al producer nuevo sin estarlo, y todos los sends siguientes fallarían.
|
|
1812
1824
|
async ensureProducerConnected() {
|
|
1813
1825
|
await this.waitForLeaderSelection();
|
|
1814
1826
|
if (this.producerConnected)
|
|
1815
1827
|
return;
|
|
1816
|
-
|
|
1817
|
-
|
|
1828
|
+
if (!this.producerConnectPromise) {
|
|
1829
|
+
const producer = this.producer;
|
|
1830
|
+
this.producerConnectPromise = producer.connect().then(() => {
|
|
1831
|
+
if (this.producer === producer) {
|
|
1832
|
+
this.producerConnected = true;
|
|
1833
|
+
}
|
|
1834
|
+
}).finally(() => {
|
|
1835
|
+
if (this.producer === producer) {
|
|
1836
|
+
this.producerConnectPromise = null;
|
|
1837
|
+
}
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1840
|
+
await this.producerConnectPromise;
|
|
1841
|
+
if (!this.producerConnected) {
|
|
1842
|
+
return this.ensureProducerConnected();
|
|
1843
|
+
}
|
|
1818
1844
|
}
|
|
1819
1845
|
initializeKafkaClients(brokers) {
|
|
1820
1846
|
this.kafka = new import_kafkajs.Kafka({
|
|
@@ -1831,6 +1857,7 @@ var KafkaManager = class extends EventManager {
|
|
|
1831
1857
|
this.producer = this.kafka.producer();
|
|
1832
1858
|
this.brokers = brokers;
|
|
1833
1859
|
this.producerConnected = false;
|
|
1860
|
+
this.producerConnectPromise = null;
|
|
1834
1861
|
this.registerConsumerEventHandlers();
|
|
1835
1862
|
}
|
|
1836
1863
|
async pinToLeaderBroker() {
|
|
@@ -2021,7 +2048,22 @@ var KafkaManager = class extends EventManager {
|
|
|
2021
2048
|
const next = (BigInt(message.offset) + 1n).toString();
|
|
2022
2049
|
await this.consumer.commitOffsets([{ topic, partition, offset: next }]);
|
|
2023
2050
|
}
|
|
2051
|
+
// Mantiene viva la sesión del consumer mientras un handler tarda más que el sessionTimeout
|
|
2052
|
+
// (default 30s de kafkajs). Sin esto, un handler lento hace que el broker expulse al consumer
|
|
2053
|
+
// a mitad de procesamiento → rebalance → el mensaje se reentrega → loop. kafkajs ya throttlea
|
|
2054
|
+
// heartbeat() internamente al heartbeatInterval, así que llamarlo de más no tiene costo.
|
|
2055
|
+
startHeartbeatLoop(heartbeat) {
|
|
2056
|
+
const interval = setInterval(() => {
|
|
2057
|
+
heartbeat().catch((error) => {
|
|
2058
|
+
console.warn("[KafkaManager] Heartbeat failed during message processing", { error: error?.message ?? error });
|
|
2059
|
+
});
|
|
2060
|
+
}, 5e3);
|
|
2061
|
+
return () => clearInterval(interval);
|
|
2062
|
+
}
|
|
2024
2063
|
async run(autocommit = false) {
|
|
2064
|
+
if (!this.hasExplicitGroupId) {
|
|
2065
|
+
throw new InternalError(ErrorManager.APP_ERRORS.PROCESS, "KAFKA_GROUP env var is required to consume. Set a unique consumer group id per service.");
|
|
2066
|
+
}
|
|
2025
2067
|
const __run = async () => {
|
|
2026
2068
|
await this.waitForLeaderSelection();
|
|
2027
2069
|
await this.execCallback(this._onStart, { message: `--- ${this.constructor.name} started ---` });
|
|
@@ -2069,7 +2111,12 @@ var KafkaManager = class extends EventManager {
|
|
|
2069
2111
|
console.log("[KafkaManager] H - before execRoute", {
|
|
2070
2112
|
offset: message.offset
|
|
2071
2113
|
});
|
|
2072
|
-
|
|
2114
|
+
const stopHeartbeatLoop = this.startHeartbeatLoop(heartbeat);
|
|
2115
|
+
try {
|
|
2116
|
+
await this.execRoute(topic, event);
|
|
2117
|
+
} finally {
|
|
2118
|
+
stopHeartbeatLoop();
|
|
2119
|
+
}
|
|
2073
2120
|
console.log("[KafkaManager] I - after execRoute", {
|
|
2074
2121
|
elapsedMs: Date.now() - execRouteStart
|
|
2075
2122
|
});
|
|
@@ -2137,8 +2184,6 @@ var KafkaManager = class extends EventManager {
|
|
|
2137
2184
|
}
|
|
2138
2185
|
]
|
|
2139
2186
|
});
|
|
2140
|
-
await this.producer.disconnect();
|
|
2141
|
-
this.producerConnected = false;
|
|
2142
2187
|
} catch (error) {
|
|
2143
2188
|
throw new InternalError(error.toString());
|
|
2144
2189
|
}
|
|
@@ -2155,6 +2200,9 @@ var KafkaManager = class extends EventManager {
|
|
|
2155
2200
|
async stop() {
|
|
2156
2201
|
await this.consumer.stop();
|
|
2157
2202
|
await this.consumer.disconnect();
|
|
2203
|
+
if (this.producerConnectPromise) {
|
|
2204
|
+
await this.producerConnectPromise.catch(() => void 0);
|
|
2205
|
+
}
|
|
2158
2206
|
if (this.producerConnected) {
|
|
2159
2207
|
await this.producer.disconnect();
|
|
2160
2208
|
this.producerConnected = false;
|
|
@@ -2366,6 +2414,7 @@ var DefaultMysqlInboxRunner = class {
|
|
|
2366
2414
|
}
|
|
2367
2415
|
async saveEvent(e, repository) {
|
|
2368
2416
|
try {
|
|
2417
|
+
console.log("[InboxRunner] BEFORE create inbox record");
|
|
2369
2418
|
let record = new InboxRecord(
|
|
2370
2419
|
UUID.create(),
|
|
2371
2420
|
e.tenant,
|
|
@@ -2374,7 +2423,9 @@ var DefaultMysqlInboxRunner = class {
|
|
|
2374
2423
|
JSON.stringify(e.message),
|
|
2375
2424
|
ProcessStatus.PENDING
|
|
2376
2425
|
);
|
|
2426
|
+
console.log("[InboxRunner] BEFORE repository.create");
|
|
2377
2427
|
await repository.create(record);
|
|
2428
|
+
console.log("[InboxRunner] AFTER repository.create");
|
|
2378
2429
|
} catch (error) {
|
|
2379
2430
|
throw error;
|
|
2380
2431
|
}
|