wsp-ms-core 1.1.22 → 1.1.24

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 CHANGED
@@ -1778,9 +1778,13 @@ var import_kafkajs = require("kafkajs");
1778
1778
  var KafkaManager = class extends EventManager {
1779
1779
  constructor(connection) {
1780
1780
  super(connection);
1781
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1782
+ this.runtimeProcess = globalThis?.process;
1781
1783
  this.producerConnected = false;
1784
+ this.exitingDueToLeaderError = false;
1785
+ this.brokers = this.resolveBrokerList(this._connection.brokers ?? []);
1782
1786
  this.kafka = new import_kafkajs.Kafka({
1783
- brokers: this._connection.brokers,
1787
+ brokers: this.brokers,
1784
1788
  ssl: true,
1785
1789
  sasl: {
1786
1790
  mechanism: "scram-sha-256",
@@ -1789,8 +1793,10 @@ var KafkaManager = class extends EventManager {
1789
1793
  },
1790
1794
  logLevel: import_kafkajs.logLevel.ERROR
1791
1795
  });
1792
- this.consumer = this.kafka.consumer({ groupId: process.env.KAFKA_GROUP || "default" });
1796
+ const groupId = this.runtimeProcess?.env?.KAFKA_GROUP || "default";
1797
+ this.consumer = this.kafka.consumer({ groupId });
1793
1798
  this.producer = this.kafka.producer();
1799
+ this.registerConsumerEventHandlers();
1794
1800
  }
1795
1801
  async ensureProducerConnected() {
1796
1802
  if (this.producerConnected)
@@ -1798,6 +1804,107 @@ var KafkaManager = class extends EventManager {
1798
1804
  await this.producer.connect();
1799
1805
  this.producerConnected = true;
1800
1806
  }
1807
+ resolveBrokerList(brokers) {
1808
+ const envBrokers = (this.runtimeProcess?.env?.KAFKA_BROKERS ?? "").split(",").map((value) => value.trim()).filter(Boolean);
1809
+ const normalized = [...brokers, ...envBrokers].map((value) => this.normalizeBroker(value)).filter((value) => Boolean(value));
1810
+ const uniqueBrokers = Array.from(new Set(normalized));
1811
+ if (!uniqueBrokers.length) {
1812
+ throw new InternalError(ErrorManager.APP_ERRORS.PROCESS, "Kafka brokers configuration is empty.");
1813
+ }
1814
+ console.info("[KafkaManager] Using brokers", uniqueBrokers);
1815
+ return uniqueBrokers;
1816
+ }
1817
+ normalizeBroker(broker) {
1818
+ if (!broker)
1819
+ return null;
1820
+ const trimmed = broker.trim();
1821
+ if (!trimmed)
1822
+ return null;
1823
+ if (trimmed.startsWith("PLAINTEXT://") || trimmed.startsWith("SSL://")) {
1824
+ return trimmed;
1825
+ }
1826
+ return trimmed.includes(":") ? trimmed : `${trimmed}:9092`;
1827
+ }
1828
+ registerConsumerEventHandlers() {
1829
+ const events = this.consumer.events;
1830
+ this.consumer.on(events.REBALANCING, async (event) => {
1831
+ await this.logConsumerEvent("REBALANCING", event);
1832
+ });
1833
+ const rebalancedEvent = this.consumer.events.REBALANCED;
1834
+ if (rebalancedEvent) {
1835
+ this.consumer.on(rebalancedEvent, async (event) => {
1836
+ await this.logConsumerEvent("REBALANCED", event);
1837
+ });
1838
+ }
1839
+ this.consumer.on(events.REQUEST_TIMEOUT, async (event) => {
1840
+ await this.logConsumerEvent("REQUEST_TIMEOUT", event, "error");
1841
+ this.handleKafkaError(event?.payload?.error, "consumer.REQUEST_TIMEOUT", { broker: event?.payload?.broker });
1842
+ });
1843
+ this.consumer.on(events.CRASH, async (event) => {
1844
+ await this.logConsumerEvent("CRASH", event, "error");
1845
+ this.handleKafkaError(event?.payload?.error, "consumer.CRASH", { broker: event?.payload?.broker });
1846
+ });
1847
+ this.consumer.on(events.DISCONNECT, async (event) => {
1848
+ await this.logConsumerEvent("DISCONNECT", event, "error");
1849
+ });
1850
+ this.consumer.on(events.CONNECT, async (event) => {
1851
+ await this.logConsumerEvent("CONNECT", event);
1852
+ });
1853
+ }
1854
+ async logConsumerEvent(eventName, kafkaEvent, level = "info") {
1855
+ const payload = kafkaEvent?.payload ?? {};
1856
+ const broker = payload?.broker ?? payload?.coordinator ?? payload?.leaderId ?? null;
1857
+ const error = payload?.error ? {
1858
+ type: payload.error.type ?? payload.error.name,
1859
+ message: payload.error.message
1860
+ } : void 0;
1861
+ const context = {
1862
+ event: eventName,
1863
+ timestamp: kafkaEvent?.timestamp ?? DateTime.now().value,
1864
+ broker,
1865
+ brokers: this.brokers,
1866
+ groupId: payload?.groupId,
1867
+ memberId: payload?.memberId,
1868
+ leaderId: payload?.leaderId,
1869
+ clientId: payload?.clientId,
1870
+ topicPartitions: payload?.topicPartitions,
1871
+ error
1872
+ };
1873
+ const message = `[KafkaManager][${eventName}] ${error?.message ?? ""}`.trim();
1874
+ if (level === "error") {
1875
+ console.error(message, context);
1876
+ await this.execCallback(this._onError, { message, context });
1877
+ } else {
1878
+ console.info(message, context);
1879
+ await this.execCallback(this._onReconnect, { message, context });
1880
+ }
1881
+ }
1882
+ handleKafkaError(error, origin, metadata = {}) {
1883
+ if (!error)
1884
+ return;
1885
+ const errorType = error.type ?? error.name;
1886
+ const isNotLeaderError = errorType === "NOT_LEADER_FOR_PARTITION" || error?.name === "KafkaJSNotLeaderForPartition";
1887
+ if (!this.exitingDueToLeaderError && isNotLeaderError) {
1888
+ this.exitingDueToLeaderError = true;
1889
+ const payload = {
1890
+ origin,
1891
+ broker: error?.broker ?? metadata?.broker,
1892
+ topic: error?.topic,
1893
+ partition: error?.partition,
1894
+ metadata
1895
+ };
1896
+ console.error("[KafkaManager][NOT_LEADER_FOR_PARTITION] Forcing shutdown", payload);
1897
+ void this.execCallback(this._onCrash, {
1898
+ message: "[KafkaManager] NOT_LEADER_FOR_PARTITION detected. Forcing shutdown.",
1899
+ context: payload
1900
+ });
1901
+ setTimeout(() => this.runtimeProcess?.exit?.(1), 0);
1902
+ return;
1903
+ }
1904
+ if (error instanceof import_kafkajs.KafkaJSRequestTimeoutError || errorType === "REQUEST_TIMEOUT") {
1905
+ console.warn("[KafkaManager][REQUEST_TIMEOUT]", { origin, metadata });
1906
+ }
1907
+ }
1801
1908
  async commitMessage(topic, partition, message) {
1802
1909
  const next = (BigInt(message.offset) + 1n).toString();
1803
1910
  await this.consumer.commitOffsets([{ topic, partition, offset: next }]);
@@ -1806,7 +1913,7 @@ var KafkaManager = class extends EventManager {
1806
1913
  const __run = async () => {
1807
1914
  await this.execCallback(this._onStart, { message: `--- ${this.constructor.name} started ---` });
1808
1915
  await this.consumer.connect();
1809
- await this.execCallback(this._onConnected, { message: `--- ${this.constructor.name} connected to ${this._connection.brokers} ---` });
1916
+ await this.execCallback(this._onConnected, { message: `--- ${this.constructor.name} connected to ${this.brokers.join(", ")} ---` });
1810
1917
  for (let topic of this._topics) {
1811
1918
  try {
1812
1919
  await this.consumer.subscribe({ topic, fromBeginning: false });
@@ -1843,6 +1950,7 @@ var KafkaManager = class extends EventManager {
1843
1950
  await heartbeat();
1844
1951
  } catch (error) {
1845
1952
  await this.execCallback(this._onError, error);
1953
+ this.handleKafkaError(error, "consumer.eachMessage", { topic, partition });
1846
1954
  throw error;
1847
1955
  }
1848
1956
  }
@@ -1883,9 +1991,6 @@ var KafkaManager = class extends EventManager {
1883
1991
  }
1884
1992
  }
1885
1993
  async start(autocommit = false) {
1886
- this.consumer.on(this.consumer.events.CRASH, async (error) => {
1887
- await this.execCallback(this._onError, new InternalError(ErrorManager.APP_ERRORS.PROCESS, error.payload.error.stack));
1888
- });
1889
1994
  await this.run();
1890
1995
  }
1891
1996
  async pause() {
@@ -2151,9 +2256,10 @@ var DefaultMysqlInboxRunner = class {
2151
2256
 
2152
2257
  // src/infrastructure/runners/default-mysql-inbox-processor.ts
2153
2258
  var DefaultMysqlInboxProcessor = class {
2154
- constructor(uowFactory) {
2259
+ constructor(uowFactory, onError) {
2155
2260
  this.uovFactory = uowFactory;
2156
2261
  this.handlers = /* @__PURE__ */ new Map();
2262
+ this.onError = onError;
2157
2263
  }
2158
2264
  async sleep() {
2159
2265
  return new Promise((r) => setTimeout(r, 5e3));
@@ -2175,6 +2281,13 @@ var DefaultMysqlInboxProcessor = class {
2175
2281
  record.markProcessed();
2176
2282
  } catch (error) {
2177
2283
  record.markWithError(error.toString());
2284
+ if (this.onError) {
2285
+ try {
2286
+ this.onError(record, error);
2287
+ } catch (handlerError) {
2288
+ console.error("Error dentro del onError handler:", handlerError);
2289
+ }
2290
+ }
2178
2291
  } finally {
2179
2292
  await repository.update(record);
2180
2293
  }