wsp-ms-core 1.1.24 → 1.1.26
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 +106 -14
- 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 +106 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -641,14 +641,23 @@ declare class HttpNotFoundController implements HttpController {
|
|
|
641
641
|
|
|
642
642
|
declare class KafkaManager extends EventManager {
|
|
643
643
|
private readonly runtimeProcess;
|
|
644
|
-
private
|
|
645
|
-
private
|
|
646
|
-
private
|
|
647
|
-
private
|
|
644
|
+
private kafka;
|
|
645
|
+
private consumer;
|
|
646
|
+
private producer;
|
|
647
|
+
private brokers;
|
|
648
|
+
private readonly seedBrokers;
|
|
649
|
+
private readonly groupId;
|
|
650
|
+
private leaderSelectionPromise;
|
|
648
651
|
private producerConnected;
|
|
649
|
-
private
|
|
652
|
+
private isRecoveringLeader;
|
|
650
653
|
constructor(connection: EventManagerConnection);
|
|
651
654
|
private ensureProducerConnected;
|
|
655
|
+
private initializeKafkaClients;
|
|
656
|
+
private pinToLeaderBroker;
|
|
657
|
+
private buildKafkaClient;
|
|
658
|
+
private fetchLeaderBroker;
|
|
659
|
+
private recoverFromLeaderChange;
|
|
660
|
+
private waitForLeaderSelection;
|
|
652
661
|
private resolveBrokerList;
|
|
653
662
|
private normalizeBroker;
|
|
654
663
|
private registerConsumerEventHandlers;
|
package/dist/index.d.ts
CHANGED
|
@@ -641,14 +641,23 @@ declare class HttpNotFoundController implements HttpController {
|
|
|
641
641
|
|
|
642
642
|
declare class KafkaManager extends EventManager {
|
|
643
643
|
private readonly runtimeProcess;
|
|
644
|
-
private
|
|
645
|
-
private
|
|
646
|
-
private
|
|
647
|
-
private
|
|
644
|
+
private kafka;
|
|
645
|
+
private consumer;
|
|
646
|
+
private producer;
|
|
647
|
+
private brokers;
|
|
648
|
+
private readonly seedBrokers;
|
|
649
|
+
private readonly groupId;
|
|
650
|
+
private leaderSelectionPromise;
|
|
648
651
|
private producerConnected;
|
|
649
|
-
private
|
|
652
|
+
private isRecoveringLeader;
|
|
650
653
|
constructor(connection: EventManagerConnection);
|
|
651
654
|
private ensureProducerConnected;
|
|
655
|
+
private initializeKafkaClients;
|
|
656
|
+
private pinToLeaderBroker;
|
|
657
|
+
private buildKafkaClient;
|
|
658
|
+
private fetchLeaderBroker;
|
|
659
|
+
private recoverFromLeaderChange;
|
|
660
|
+
private waitForLeaderSelection;
|
|
652
661
|
private resolveBrokerList;
|
|
653
662
|
private normalizeBroker;
|
|
654
663
|
private registerConsumerEventHandlers;
|
package/dist/index.js
CHANGED
|
@@ -1709,10 +1709,22 @@ var KafkaManager = class extends EventManager {
|
|
|
1709
1709
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1710
1710
|
this.runtimeProcess = globalThis?.process;
|
|
1711
1711
|
this.producerConnected = false;
|
|
1712
|
-
this.
|
|
1713
|
-
this.
|
|
1712
|
+
this.isRecoveringLeader = false;
|
|
1713
|
+
this.seedBrokers = this.resolveBrokerList(this._connection.brokers ?? []);
|
|
1714
|
+
this.groupId = this.runtimeProcess?.env?.KAFKA_GROUP || "default";
|
|
1715
|
+
this.initializeKafkaClients(this.seedBrokers);
|
|
1716
|
+
this.leaderSelectionPromise = this.pinToLeaderBroker();
|
|
1717
|
+
}
|
|
1718
|
+
async ensureProducerConnected() {
|
|
1719
|
+
await this.waitForLeaderSelection();
|
|
1720
|
+
if (this.producerConnected)
|
|
1721
|
+
return;
|
|
1722
|
+
await this.producer.connect();
|
|
1723
|
+
this.producerConnected = true;
|
|
1724
|
+
}
|
|
1725
|
+
initializeKafkaClients(brokers) {
|
|
1714
1726
|
this.kafka = new Kafka({
|
|
1715
|
-
brokers
|
|
1727
|
+
brokers,
|
|
1716
1728
|
ssl: true,
|
|
1717
1729
|
sasl: {
|
|
1718
1730
|
mechanism: "scram-sha-256",
|
|
@@ -1721,16 +1733,92 @@ var KafkaManager = class extends EventManager {
|
|
|
1721
1733
|
},
|
|
1722
1734
|
logLevel: logLevel.ERROR
|
|
1723
1735
|
});
|
|
1724
|
-
|
|
1725
|
-
this.consumer = this.kafka.consumer({ groupId });
|
|
1736
|
+
this.consumer = this.kafka.consumer({ groupId: this.groupId });
|
|
1726
1737
|
this.producer = this.kafka.producer();
|
|
1738
|
+
this.brokers = brokers;
|
|
1739
|
+
this.producerConnected = false;
|
|
1727
1740
|
this.registerConsumerEventHandlers();
|
|
1728
1741
|
}
|
|
1729
|
-
async
|
|
1730
|
-
|
|
1742
|
+
async pinToLeaderBroker() {
|
|
1743
|
+
try {
|
|
1744
|
+
const leaderBroker = await this.fetchLeaderBroker(this.kafka);
|
|
1745
|
+
if (!leaderBroker) {
|
|
1746
|
+
console.warn("[KafkaManager] Unable to determine leader broker. Using configured list.", { brokers: this.brokers });
|
|
1747
|
+
return;
|
|
1748
|
+
}
|
|
1749
|
+
if (this.brokers.length === 1 && this.brokers[0] === leaderBroker) {
|
|
1750
|
+
return;
|
|
1751
|
+
}
|
|
1752
|
+
console.info("[KafkaManager] Leader broker resolved. Reinitializing clients", { leaderBroker });
|
|
1753
|
+
this.initializeKafkaClients([leaderBroker]);
|
|
1754
|
+
} catch (error) {
|
|
1755
|
+
console.warn("[KafkaManager] Error resolving leader broker. Falling back to configured brokers.", error);
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
buildKafkaClient(brokers) {
|
|
1759
|
+
return new Kafka({
|
|
1760
|
+
brokers,
|
|
1761
|
+
ssl: true,
|
|
1762
|
+
sasl: {
|
|
1763
|
+
mechanism: "scram-sha-256",
|
|
1764
|
+
username: this._connection.userName,
|
|
1765
|
+
password: this._connection.password
|
|
1766
|
+
},
|
|
1767
|
+
logLevel: logLevel.ERROR
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
async fetchLeaderBroker(kafkaClient) {
|
|
1771
|
+
const admin = kafkaClient.admin();
|
|
1772
|
+
try {
|
|
1773
|
+
await admin.connect();
|
|
1774
|
+
const cluster = await admin.describeCluster();
|
|
1775
|
+
const controllerId = cluster?.controller;
|
|
1776
|
+
const controller = controllerId !== void 0 ? cluster?.brokers?.find((node) => node.nodeId === controllerId) : void 0;
|
|
1777
|
+
if (!controller?.host) {
|
|
1778
|
+
return null;
|
|
1779
|
+
}
|
|
1780
|
+
const host = controller.host;
|
|
1781
|
+
const port = controller.port ?? 9092;
|
|
1782
|
+
return this.normalizeBroker(`${host}:${port}`);
|
|
1783
|
+
} finally {
|
|
1784
|
+
await admin.disconnect().catch(() => void 0);
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
async recoverFromLeaderChange(origin) {
|
|
1788
|
+
if (this.isRecoveringLeader)
|
|
1731
1789
|
return;
|
|
1732
|
-
|
|
1733
|
-
this.
|
|
1790
|
+
this.isRecoveringLeader = true;
|
|
1791
|
+
console.warn("[KafkaManager] Recovering from leader change", { origin, brokers: this.brokers });
|
|
1792
|
+
await this.execCallback(this._onReconnect, {
|
|
1793
|
+
message: "[KafkaManager] Leader change detected. Reconnecting to new leader.",
|
|
1794
|
+
context: { origin }
|
|
1795
|
+
});
|
|
1796
|
+
try {
|
|
1797
|
+
await this.stop().catch((error) => {
|
|
1798
|
+
console.warn("[KafkaManager] Error stopping previous connection during recovery", error);
|
|
1799
|
+
});
|
|
1800
|
+
const seedClient = this.buildKafkaClient(this.seedBrokers);
|
|
1801
|
+
const leaderBroker = await this.fetchLeaderBroker(seedClient).catch((error) => {
|
|
1802
|
+
console.warn("[KafkaManager] Error resolving new leader broker during recovery", error);
|
|
1803
|
+
return null;
|
|
1804
|
+
});
|
|
1805
|
+
const brokersToUse = leaderBroker ? [leaderBroker] : this.seedBrokers;
|
|
1806
|
+
console.info("[KafkaManager] Reconnecting using brokers", { brokersToUse });
|
|
1807
|
+
this.initializeKafkaClients(brokersToUse);
|
|
1808
|
+
this.leaderSelectionPromise = Promise.resolve();
|
|
1809
|
+
await this.run();
|
|
1810
|
+
} catch (error) {
|
|
1811
|
+
console.error("[KafkaManager] Failed to recover from leader change", { origin, error });
|
|
1812
|
+
await this.execCallback(this._onError, error);
|
|
1813
|
+
} finally {
|
|
1814
|
+
this.isRecoveringLeader = false;
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
async waitForLeaderSelection() {
|
|
1818
|
+
try {
|
|
1819
|
+
await this.leaderSelectionPromise;
|
|
1820
|
+
} catch {
|
|
1821
|
+
}
|
|
1734
1822
|
}
|
|
1735
1823
|
resolveBrokerList(brokers) {
|
|
1736
1824
|
const envBrokers = (this.runtimeProcess?.env?.KAFKA_BROKERS ?? "").split(",").map((value) => value.trim()).filter(Boolean);
|
|
@@ -1771,6 +1859,9 @@ var KafkaManager = class extends EventManager {
|
|
|
1771
1859
|
this.consumer.on(events.CRASH, async (event) => {
|
|
1772
1860
|
await this.logConsumerEvent("CRASH", event, "error");
|
|
1773
1861
|
this.handleKafkaError(event?.payload?.error, "consumer.CRASH", { broker: event?.payload?.broker });
|
|
1862
|
+
if (event?.payload?.restart === false) {
|
|
1863
|
+
void this.recoverFromLeaderChange("consumer.CRASH.no-restart");
|
|
1864
|
+
}
|
|
1774
1865
|
});
|
|
1775
1866
|
this.consumer.on(events.DISCONNECT, async (event) => {
|
|
1776
1867
|
await this.logConsumerEvent("DISCONNECT", event, "error");
|
|
@@ -1812,8 +1903,7 @@ var KafkaManager = class extends EventManager {
|
|
|
1812
1903
|
return;
|
|
1813
1904
|
const errorType = error.type ?? error.name;
|
|
1814
1905
|
const isNotLeaderError = errorType === "NOT_LEADER_FOR_PARTITION" || error?.name === "KafkaJSNotLeaderForPartition";
|
|
1815
|
-
if (
|
|
1816
|
-
this.exitingDueToLeaderError = true;
|
|
1906
|
+
if (isNotLeaderError) {
|
|
1817
1907
|
const payload = {
|
|
1818
1908
|
origin,
|
|
1819
1909
|
broker: error?.broker ?? metadata?.broker,
|
|
@@ -1821,12 +1911,12 @@ var KafkaManager = class extends EventManager {
|
|
|
1821
1911
|
partition: error?.partition,
|
|
1822
1912
|
metadata
|
|
1823
1913
|
};
|
|
1824
|
-
console.error("[KafkaManager][NOT_LEADER_FOR_PARTITION]
|
|
1914
|
+
console.error("[KafkaManager][NOT_LEADER_FOR_PARTITION] Reconnecting to new leader", payload);
|
|
1825
1915
|
void this.execCallback(this._onCrash, {
|
|
1826
|
-
message: "[KafkaManager] NOT_LEADER_FOR_PARTITION detected.
|
|
1916
|
+
message: "[KafkaManager] NOT_LEADER_FOR_PARTITION detected. Reconnecting to new leader.",
|
|
1827
1917
|
context: payload
|
|
1828
1918
|
});
|
|
1829
|
-
|
|
1919
|
+
void this.recoverFromLeaderChange(origin);
|
|
1830
1920
|
return;
|
|
1831
1921
|
}
|
|
1832
1922
|
if (error instanceof KafkaJSRequestTimeoutError || errorType === "REQUEST_TIMEOUT") {
|
|
@@ -1839,6 +1929,7 @@ var KafkaManager = class extends EventManager {
|
|
|
1839
1929
|
}
|
|
1840
1930
|
async run(autocommit = false) {
|
|
1841
1931
|
const __run = async () => {
|
|
1932
|
+
await this.waitForLeaderSelection();
|
|
1842
1933
|
await this.execCallback(this._onStart, { message: `--- ${this.constructor.name} started ---` });
|
|
1843
1934
|
await this.consumer.connect();
|
|
1844
1935
|
await this.execCallback(this._onConnected, { message: `--- ${this.constructor.name} connected to ${this.brokers.join(", ")} ---` });
|
|
@@ -1891,6 +1982,7 @@ var KafkaManager = class extends EventManager {
|
|
|
1891
1982
|
}
|
|
1892
1983
|
}
|
|
1893
1984
|
async send(e) {
|
|
1985
|
+
await this.waitForLeaderSelection();
|
|
1894
1986
|
const evt = {
|
|
1895
1987
|
date: DateTime.now().value,
|
|
1896
1988
|
tenant: e.tenant.value,
|