wsp-ms-core 1.1.24 → 1.1.27
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 +188 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +14 -5
- package/dist/index.d.ts +14 -5
- package/dist/index.js +188 -35
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1320,8 +1320,30 @@ var EventManager = class {
|
|
|
1320
1320
|
this._onReconnect = null;
|
|
1321
1321
|
}
|
|
1322
1322
|
async execRoute(topic, event) {
|
|
1323
|
-
|
|
1324
|
-
|
|
1323
|
+
console.log("[KafkaManager] execRoute START", {
|
|
1324
|
+
topic
|
|
1325
|
+
});
|
|
1326
|
+
const callback = this._callbackList[topic];
|
|
1327
|
+
if (!callback) {
|
|
1328
|
+
console.log("[KafkaManager] execRoute NO CALLBACK", {
|
|
1329
|
+
topic
|
|
1330
|
+
});
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1333
|
+
const start = Date.now();
|
|
1334
|
+
try {
|
|
1335
|
+
await callback(event);
|
|
1336
|
+
console.log("[KafkaManager] execRoute END", {
|
|
1337
|
+
topic,
|
|
1338
|
+
elapsedMs: Date.now() - start
|
|
1339
|
+
});
|
|
1340
|
+
} catch (e) {
|
|
1341
|
+
console.error("[KafkaManager] execRoute ERROR", {
|
|
1342
|
+
topic,
|
|
1343
|
+
elapsedMs: Date.now() - start,
|
|
1344
|
+
error: e
|
|
1345
|
+
});
|
|
1346
|
+
throw e;
|
|
1325
1347
|
}
|
|
1326
1348
|
}
|
|
1327
1349
|
async execCallback(callback, data) {
|
|
@@ -1781,10 +1803,22 @@ var KafkaManager = class extends EventManager {
|
|
|
1781
1803
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1782
1804
|
this.runtimeProcess = globalThis?.process;
|
|
1783
1805
|
this.producerConnected = false;
|
|
1784
|
-
this.
|
|
1785
|
-
this.
|
|
1806
|
+
this.isRecoveringLeader = false;
|
|
1807
|
+
this.seedBrokers = this.resolveBrokerList(this._connection.brokers ?? []);
|
|
1808
|
+
this.groupId = this.runtimeProcess?.env?.KAFKA_GROUP || "default";
|
|
1809
|
+
this.initializeKafkaClients(this.seedBrokers);
|
|
1810
|
+
this.leaderSelectionPromise = this.pinToLeaderBroker();
|
|
1811
|
+
}
|
|
1812
|
+
async ensureProducerConnected() {
|
|
1813
|
+
await this.waitForLeaderSelection();
|
|
1814
|
+
if (this.producerConnected)
|
|
1815
|
+
return;
|
|
1816
|
+
await this.producer.connect();
|
|
1817
|
+
this.producerConnected = true;
|
|
1818
|
+
}
|
|
1819
|
+
initializeKafkaClients(brokers) {
|
|
1786
1820
|
this.kafka = new import_kafkajs.Kafka({
|
|
1787
|
-
brokers
|
|
1821
|
+
brokers,
|
|
1788
1822
|
ssl: true,
|
|
1789
1823
|
sasl: {
|
|
1790
1824
|
mechanism: "scram-sha-256",
|
|
@@ -1793,16 +1827,92 @@ var KafkaManager = class extends EventManager {
|
|
|
1793
1827
|
},
|
|
1794
1828
|
logLevel: import_kafkajs.logLevel.ERROR
|
|
1795
1829
|
});
|
|
1796
|
-
|
|
1797
|
-
this.consumer = this.kafka.consumer({ groupId });
|
|
1830
|
+
this.consumer = this.kafka.consumer({ groupId: this.groupId });
|
|
1798
1831
|
this.producer = this.kafka.producer();
|
|
1832
|
+
this.brokers = brokers;
|
|
1833
|
+
this.producerConnected = false;
|
|
1799
1834
|
this.registerConsumerEventHandlers();
|
|
1800
1835
|
}
|
|
1801
|
-
async
|
|
1802
|
-
|
|
1836
|
+
async pinToLeaderBroker() {
|
|
1837
|
+
try {
|
|
1838
|
+
const leaderBroker = await this.fetchLeaderBroker(this.kafka);
|
|
1839
|
+
if (!leaderBroker) {
|
|
1840
|
+
console.warn("[KafkaManager] Unable to determine leader broker. Using configured list.", { brokers: this.brokers });
|
|
1841
|
+
return;
|
|
1842
|
+
}
|
|
1843
|
+
if (this.brokers.length === 1 && this.brokers[0] === leaderBroker) {
|
|
1844
|
+
return;
|
|
1845
|
+
}
|
|
1846
|
+
console.info("[KafkaManager] Leader broker resolved. Reinitializing clients", { leaderBroker });
|
|
1847
|
+
this.initializeKafkaClients([leaderBroker]);
|
|
1848
|
+
} catch (error) {
|
|
1849
|
+
console.warn("[KafkaManager] Error resolving leader broker. Falling back to configured brokers.", error);
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
buildKafkaClient(brokers) {
|
|
1853
|
+
return new import_kafkajs.Kafka({
|
|
1854
|
+
brokers,
|
|
1855
|
+
ssl: true,
|
|
1856
|
+
sasl: {
|
|
1857
|
+
mechanism: "scram-sha-256",
|
|
1858
|
+
username: this._connection.userName,
|
|
1859
|
+
password: this._connection.password
|
|
1860
|
+
},
|
|
1861
|
+
logLevel: import_kafkajs.logLevel.ERROR
|
|
1862
|
+
});
|
|
1863
|
+
}
|
|
1864
|
+
async fetchLeaderBroker(kafkaClient) {
|
|
1865
|
+
const admin = kafkaClient.admin();
|
|
1866
|
+
try {
|
|
1867
|
+
await admin.connect();
|
|
1868
|
+
const cluster = await admin.describeCluster();
|
|
1869
|
+
const controllerId = cluster?.controller;
|
|
1870
|
+
const controller = controllerId !== void 0 ? cluster?.brokers?.find((node) => node.nodeId === controllerId) : void 0;
|
|
1871
|
+
if (!controller?.host) {
|
|
1872
|
+
return null;
|
|
1873
|
+
}
|
|
1874
|
+
const host = controller.host;
|
|
1875
|
+
const port = controller.port ?? 9092;
|
|
1876
|
+
return this.normalizeBroker(`${host}:${port}`);
|
|
1877
|
+
} finally {
|
|
1878
|
+
await admin.disconnect().catch(() => void 0);
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
async recoverFromLeaderChange(origin) {
|
|
1882
|
+
if (this.isRecoveringLeader)
|
|
1803
1883
|
return;
|
|
1804
|
-
|
|
1805
|
-
this.
|
|
1884
|
+
this.isRecoveringLeader = true;
|
|
1885
|
+
console.warn("[KafkaManager] Recovering from leader change", { origin, brokers: this.brokers });
|
|
1886
|
+
await this.execCallback(this._onReconnect, {
|
|
1887
|
+
message: "[KafkaManager] Leader change detected. Reconnecting to new leader.",
|
|
1888
|
+
context: { origin }
|
|
1889
|
+
});
|
|
1890
|
+
try {
|
|
1891
|
+
await this.stop().catch((error) => {
|
|
1892
|
+
console.warn("[KafkaManager] Error stopping previous connection during recovery", error);
|
|
1893
|
+
});
|
|
1894
|
+
const seedClient = this.buildKafkaClient(this.seedBrokers);
|
|
1895
|
+
const leaderBroker = await this.fetchLeaderBroker(seedClient).catch((error) => {
|
|
1896
|
+
console.warn("[KafkaManager] Error resolving new leader broker during recovery", error);
|
|
1897
|
+
return null;
|
|
1898
|
+
});
|
|
1899
|
+
const brokersToUse = leaderBroker ? [leaderBroker] : this.seedBrokers;
|
|
1900
|
+
console.info("[KafkaManager] Reconnecting using brokers", { brokersToUse });
|
|
1901
|
+
this.initializeKafkaClients(brokersToUse);
|
|
1902
|
+
this.leaderSelectionPromise = Promise.resolve();
|
|
1903
|
+
await this.run();
|
|
1904
|
+
} catch (error) {
|
|
1905
|
+
console.error("[KafkaManager] Failed to recover from leader change", { origin, error });
|
|
1906
|
+
await this.execCallback(this._onError, error);
|
|
1907
|
+
} finally {
|
|
1908
|
+
this.isRecoveringLeader = false;
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
async waitForLeaderSelection() {
|
|
1912
|
+
try {
|
|
1913
|
+
await this.leaderSelectionPromise;
|
|
1914
|
+
} catch {
|
|
1915
|
+
}
|
|
1806
1916
|
}
|
|
1807
1917
|
resolveBrokerList(brokers) {
|
|
1808
1918
|
const envBrokers = (this.runtimeProcess?.env?.KAFKA_BROKERS ?? "").split(",").map((value) => value.trim()).filter(Boolean);
|
|
@@ -1843,6 +1953,9 @@ var KafkaManager = class extends EventManager {
|
|
|
1843
1953
|
this.consumer.on(events.CRASH, async (event) => {
|
|
1844
1954
|
await this.logConsumerEvent("CRASH", event, "error");
|
|
1845
1955
|
this.handleKafkaError(event?.payload?.error, "consumer.CRASH", { broker: event?.payload?.broker });
|
|
1956
|
+
if (event?.payload?.restart === false) {
|
|
1957
|
+
void this.recoverFromLeaderChange("consumer.CRASH.no-restart");
|
|
1958
|
+
}
|
|
1846
1959
|
});
|
|
1847
1960
|
this.consumer.on(events.DISCONNECT, async (event) => {
|
|
1848
1961
|
await this.logConsumerEvent("DISCONNECT", event, "error");
|
|
@@ -1884,8 +1997,7 @@ var KafkaManager = class extends EventManager {
|
|
|
1884
1997
|
return;
|
|
1885
1998
|
const errorType = error.type ?? error.name;
|
|
1886
1999
|
const isNotLeaderError = errorType === "NOT_LEADER_FOR_PARTITION" || error?.name === "KafkaJSNotLeaderForPartition";
|
|
1887
|
-
if (
|
|
1888
|
-
this.exitingDueToLeaderError = true;
|
|
2000
|
+
if (isNotLeaderError) {
|
|
1889
2001
|
const payload = {
|
|
1890
2002
|
origin,
|
|
1891
2003
|
broker: error?.broker ?? metadata?.broker,
|
|
@@ -1893,12 +2005,12 @@ var KafkaManager = class extends EventManager {
|
|
|
1893
2005
|
partition: error?.partition,
|
|
1894
2006
|
metadata
|
|
1895
2007
|
};
|
|
1896
|
-
console.error("[KafkaManager][NOT_LEADER_FOR_PARTITION]
|
|
2008
|
+
console.error("[KafkaManager][NOT_LEADER_FOR_PARTITION] Reconnecting to new leader", payload);
|
|
1897
2009
|
void this.execCallback(this._onCrash, {
|
|
1898
|
-
message: "[KafkaManager] NOT_LEADER_FOR_PARTITION detected.
|
|
2010
|
+
message: "[KafkaManager] NOT_LEADER_FOR_PARTITION detected. Reconnecting to new leader.",
|
|
1899
2011
|
context: payload
|
|
1900
2012
|
});
|
|
1901
|
-
|
|
2013
|
+
void this.recoverFromLeaderChange(origin);
|
|
1902
2014
|
return;
|
|
1903
2015
|
}
|
|
1904
2016
|
if (error instanceof import_kafkajs.KafkaJSRequestTimeoutError || errorType === "REQUEST_TIMEOUT") {
|
|
@@ -1911,6 +2023,7 @@ var KafkaManager = class extends EventManager {
|
|
|
1911
2023
|
}
|
|
1912
2024
|
async run(autocommit = false) {
|
|
1913
2025
|
const __run = async () => {
|
|
2026
|
+
await this.waitForLeaderSelection();
|
|
1914
2027
|
await this.execCallback(this._onStart, { message: `--- ${this.constructor.name} started ---` });
|
|
1915
2028
|
await this.consumer.connect();
|
|
1916
2029
|
await this.execCallback(this._onConnected, { message: `--- ${this.constructor.name} connected to ${this.brokers.join(", ")} ---` });
|
|
@@ -1926,31 +2039,70 @@ var KafkaManager = class extends EventManager {
|
|
|
1926
2039
|
autoCommit: false,
|
|
1927
2040
|
// @ts-ignore
|
|
1928
2041
|
eachMessage: async ({ topic, partition, message, heartbeat }) => {
|
|
2042
|
+
console.log("[KafkaManager] A - eachMessage START", {
|
|
2043
|
+
topic,
|
|
2044
|
+
partition,
|
|
2045
|
+
offset: message.offset
|
|
2046
|
+
});
|
|
1929
2047
|
try {
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
message: json.data
|
|
1942
|
-
};
|
|
1943
|
-
} catch (error) {
|
|
1944
|
-
await this.commitMessage(topic, partition, message);
|
|
1945
|
-
await heartbeat();
|
|
1946
|
-
throw error;
|
|
2048
|
+
console.log("[KafkaManager] B - before execCallback(_onMessage)");
|
|
2049
|
+
await this.execCallback(
|
|
2050
|
+
this._onMessage,
|
|
2051
|
+
`[New message detected for ${topic}]: ${message.value?.toString()}`
|
|
2052
|
+
);
|
|
2053
|
+
console.log("[KafkaManager] C - after execCallback(_onMessage)");
|
|
2054
|
+
console.log("[KafkaManager] D - before JSON.parse");
|
|
2055
|
+
const json = JSON.parse(message.value.toString());
|
|
2056
|
+
console.log("[KafkaManager] E - after JSON.parse");
|
|
2057
|
+
if (!json.data) {
|
|
2058
|
+
json.data = {};
|
|
1947
2059
|
}
|
|
2060
|
+
console.log("[KafkaManager] F - before EventMessage creation");
|
|
2061
|
+
const event = {
|
|
2062
|
+
topic: String(topic),
|
|
2063
|
+
producer: String(json.producer),
|
|
2064
|
+
tenant: UUID.create(String(json.tenant)),
|
|
2065
|
+
message: json.data
|
|
2066
|
+
};
|
|
2067
|
+
console.log("[KafkaManager] G - EventMessage created");
|
|
2068
|
+
const execRouteStart = Date.now();
|
|
2069
|
+
console.log("[KafkaManager] H - before execRoute", {
|
|
2070
|
+
offset: message.offset
|
|
2071
|
+
});
|
|
1948
2072
|
await this.execRoute(topic, event);
|
|
2073
|
+
console.log("[KafkaManager] I - after execRoute", {
|
|
2074
|
+
elapsedMs: Date.now() - execRouteStart
|
|
2075
|
+
});
|
|
2076
|
+
const commitStart = Date.now();
|
|
2077
|
+
console.log("[KafkaManager] J - before commitMessage");
|
|
1949
2078
|
await this.commitMessage(topic, partition, message);
|
|
2079
|
+
console.log("[KafkaManager] K - after commitMessage", {
|
|
2080
|
+
elapsedMs: Date.now() - commitStart
|
|
2081
|
+
});
|
|
2082
|
+
const hbStart = Date.now();
|
|
2083
|
+
console.log("[KafkaManager] L - before heartbeat");
|
|
1950
2084
|
await heartbeat();
|
|
2085
|
+
console.log("[KafkaManager] M - after heartbeat", {
|
|
2086
|
+
elapsedMs: Date.now() - hbStart
|
|
2087
|
+
});
|
|
2088
|
+
console.log("[KafkaManager] N - eachMessage END");
|
|
1951
2089
|
} catch (error) {
|
|
1952
|
-
|
|
1953
|
-
|
|
2090
|
+
console.error("[KafkaManager] ERROR inside eachMessage", {
|
|
2091
|
+
topic,
|
|
2092
|
+
partition,
|
|
2093
|
+
offset: message.offset,
|
|
2094
|
+
error
|
|
2095
|
+
});
|
|
2096
|
+
try {
|
|
2097
|
+
await this.execCallback(this._onError, error);
|
|
2098
|
+
} catch (callbackError) {
|
|
2099
|
+
console.error("[KafkaManager] ERROR executing _onError callback", callbackError);
|
|
2100
|
+
}
|
|
2101
|
+
this.handleKafkaError(error, "consumer.eachMessage", {
|
|
2102
|
+
topic,
|
|
2103
|
+
partition,
|
|
2104
|
+
offset: message.offset
|
|
2105
|
+
});
|
|
1954
2106
|
throw error;
|
|
1955
2107
|
}
|
|
1956
2108
|
}
|
|
@@ -1963,6 +2115,7 @@ var KafkaManager = class extends EventManager {
|
|
|
1963
2115
|
}
|
|
1964
2116
|
}
|
|
1965
2117
|
async send(e) {
|
|
2118
|
+
await this.waitForLeaderSelection();
|
|
1966
2119
|
const evt = {
|
|
1967
2120
|
date: DateTime.now().value,
|
|
1968
2121
|
tenant: e.tenant.value,
|