@514labs/moose-lib 0.6.252-ci-4-gb8a461bd → 0.6.252-ci-2-g41538689
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/{browserCompatible-CYDIQRRZ.d.mts → browserCompatible-BTN82akc.d.mts} +1 -1
- package/dist/{browserCompatible-C_H_-QHB.d.ts → browserCompatible-CoxWbneN.d.ts} +1 -1
- package/dist/browserCompatible.d.mts +2 -2
- package/dist/browserCompatible.d.ts +2 -2
- package/dist/browserCompatible.js +14 -6
- package/dist/browserCompatible.js.map +1 -1
- package/dist/browserCompatible.mjs +14 -6
- package/dist/browserCompatible.mjs.map +1 -1
- package/dist/compilerPlugin.js.map +1 -1
- package/dist/compilerPlugin.mjs.map +1 -1
- package/dist/dmv2/index.d.mts +1 -1
- package/dist/dmv2/index.d.ts +1 -1
- package/dist/dmv2/index.js +14 -6
- package/dist/dmv2/index.js.map +1 -1
- package/dist/dmv2/index.mjs +14 -6
- package/dist/dmv2/index.mjs.map +1 -1
- package/dist/{index-xC52kbse.d.mts → index-CNlTyF6R.d.mts} +1 -101
- package/dist/{index-xC52kbse.d.ts → index-CNlTyF6R.d.ts} +1 -101
- package/dist/index.d.mts +28 -5
- package/dist/index.d.ts +28 -5
- package/dist/index.js +16 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +15 -7
- package/dist/index.mjs.map +1 -1
- package/dist/moose-runner.js +100 -217
- package/dist/moose-runner.js.map +1 -1
- package/dist/moose-runner.mjs +100 -217
- package/dist/moose-runner.mjs.map +1 -1
- package/package.json +1 -1
package/dist/moose-runner.js
CHANGED
|
@@ -39,6 +39,22 @@ function isTruthy(value) {
|
|
|
39
39
|
return false;
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
function createProducerConfig(maxMessageBytes) {
|
|
43
|
+
return {
|
|
44
|
+
kafkaJS: {
|
|
45
|
+
idempotent: false,
|
|
46
|
+
// Not needed for at-least-once delivery
|
|
47
|
+
acks: ACKs,
|
|
48
|
+
retry: {
|
|
49
|
+
retries: MAX_RETRIES_PRODUCER,
|
|
50
|
+
maxRetryTime: MAX_RETRY_TIME_MS
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"linger.ms": 0,
|
|
54
|
+
// Send immediately - batching happens at application level
|
|
55
|
+
...maxMessageBytes && { "message.max.bytes": maxMessageBytes }
|
|
56
|
+
};
|
|
57
|
+
}
|
|
42
58
|
var import_http, import_client, import_kafka_javascript, Kafka, compilerLog, getClickhouseClient, cliLog, MAX_RETRIES, MAX_RETRY_TIME_MS, RETRY_INITIAL_TIME_MS, MAX_RETRIES_PRODUCER, ACKs, parseBrokerString, logError, buildSaslConfig, getKafkaClient;
|
|
43
59
|
var init_commons = __esm({
|
|
44
60
|
"src/commons.ts"() {
|
|
@@ -1322,18 +1338,6 @@ function convertIcebergS3EngineConfig(config) {
|
|
|
1322
1338
|
compression: config.compression
|
|
1323
1339
|
};
|
|
1324
1340
|
}
|
|
1325
|
-
function convertKafkaEngineConfig(config) {
|
|
1326
|
-
if (!("engine" in config) || config.engine !== "Kafka" /* Kafka */) {
|
|
1327
|
-
return void 0;
|
|
1328
|
-
}
|
|
1329
|
-
return {
|
|
1330
|
-
engine: "Kafka",
|
|
1331
|
-
brokerList: config.brokerList,
|
|
1332
|
-
topicList: config.topicList,
|
|
1333
|
-
groupName: config.groupName,
|
|
1334
|
-
format: config.format
|
|
1335
|
-
};
|
|
1336
|
-
}
|
|
1337
1341
|
function convertTableConfigToEngineConfig(config) {
|
|
1338
1342
|
const engine = extractEngineValue(config);
|
|
1339
1343
|
const basicConfig = convertBasicEngineConfig(engine, config);
|
|
@@ -1359,9 +1363,6 @@ function convertTableConfigToEngineConfig(config) {
|
|
|
1359
1363
|
if (engine === "IcebergS3" /* IcebergS3 */) {
|
|
1360
1364
|
return convertIcebergS3EngineConfig(config);
|
|
1361
1365
|
}
|
|
1362
|
-
if (engine === "Kafka" /* Kafka */) {
|
|
1363
|
-
return convertKafkaEngineConfig(config);
|
|
1364
|
-
}
|
|
1365
1366
|
return void 0;
|
|
1366
1367
|
}
|
|
1367
1368
|
var toInfraMap = (registry) => {
|
|
@@ -1831,156 +1832,6 @@ var MAX_RETRIES_CONSUMER = 150;
|
|
|
1831
1832
|
var SESSION_TIMEOUT_CONSUMER = 3e4;
|
|
1832
1833
|
var HEARTBEAT_INTERVAL_CONSUMER = 3e3;
|
|
1833
1834
|
var DEFAULT_MAX_STREAMING_CONCURRENCY = 100;
|
|
1834
|
-
var KAFKAJS_BYTE_MESSAGE_OVERHEAD = 500;
|
|
1835
|
-
var isMessageTooLargeError = (error) => {
|
|
1836
|
-
if (import_kafka_javascript2.KafkaJS.isKafkaJSError && error instanceof Error && import_kafka_javascript2.KafkaJS.isKafkaJSError(error)) {
|
|
1837
|
-
return error.type === "ERR_MSG_SIZE_TOO_LARGE" || error.code === 10 || error.cause !== void 0 && isMessageTooLargeError(error.cause);
|
|
1838
|
-
}
|
|
1839
|
-
if (error && typeof error === "object") {
|
|
1840
|
-
const err = error;
|
|
1841
|
-
return err.type === "ERR_MSG_SIZE_TOO_LARGE" || err.code === 10 || err.cause !== void 0 && isMessageTooLargeError(err.cause);
|
|
1842
|
-
}
|
|
1843
|
-
return false;
|
|
1844
|
-
};
|
|
1845
|
-
var splitBatch = (messages, maxChunkSize) => {
|
|
1846
|
-
if (messages.length <= 1) {
|
|
1847
|
-
return [messages];
|
|
1848
|
-
}
|
|
1849
|
-
const chunks = [];
|
|
1850
|
-
let currentChunk = [];
|
|
1851
|
-
let currentSize = 0;
|
|
1852
|
-
for (const message of messages) {
|
|
1853
|
-
const messageSize = import_node_buffer.Buffer.byteLength(message.value, "utf8") + KAFKAJS_BYTE_MESSAGE_OVERHEAD;
|
|
1854
|
-
if (currentSize + messageSize > maxChunkSize && currentChunk.length > 0) {
|
|
1855
|
-
chunks.push(currentChunk);
|
|
1856
|
-
currentChunk = [message];
|
|
1857
|
-
currentSize = messageSize;
|
|
1858
|
-
} else {
|
|
1859
|
-
currentChunk.push(message);
|
|
1860
|
-
currentSize += messageSize;
|
|
1861
|
-
}
|
|
1862
|
-
}
|
|
1863
|
-
if (currentChunk.length > 0) {
|
|
1864
|
-
chunks.push(currentChunk);
|
|
1865
|
-
}
|
|
1866
|
-
return chunks;
|
|
1867
|
-
};
|
|
1868
|
-
var sendChunkWithRetry = async (logger2, targetTopic, producer, messages, currentMaxSize, maxRetries = 3) => {
|
|
1869
|
-
const currentMessages = messages;
|
|
1870
|
-
let attempts = 0;
|
|
1871
|
-
while (attempts < maxRetries) {
|
|
1872
|
-
try {
|
|
1873
|
-
await producer.send({
|
|
1874
|
-
topic: targetTopic.name,
|
|
1875
|
-
messages: currentMessages
|
|
1876
|
-
});
|
|
1877
|
-
logger2.log(
|
|
1878
|
-
`Successfully sent ${currentMessages.length} messages to ${targetTopic.name}`
|
|
1879
|
-
);
|
|
1880
|
-
return;
|
|
1881
|
-
} catch (error) {
|
|
1882
|
-
if (isMessageTooLargeError(error) && currentMessages.length > 1) {
|
|
1883
|
-
logger2.warn(
|
|
1884
|
-
`Got MESSAGE_TOO_LARGE error, splitting batch of ${currentMessages.length} messages and retrying (${maxRetries - attempts} attempts left)`
|
|
1885
|
-
);
|
|
1886
|
-
const newMaxSize = Math.floor(currentMaxSize / 2);
|
|
1887
|
-
const splitChunks = splitBatch(currentMessages, newMaxSize);
|
|
1888
|
-
for (const chunk of splitChunks) {
|
|
1889
|
-
await sendChunkWithRetry(
|
|
1890
|
-
logger2,
|
|
1891
|
-
targetTopic,
|
|
1892
|
-
producer,
|
|
1893
|
-
chunk,
|
|
1894
|
-
newMaxSize,
|
|
1895
|
-
// this error does not count as one failed attempt
|
|
1896
|
-
maxRetries - attempts
|
|
1897
|
-
);
|
|
1898
|
-
}
|
|
1899
|
-
return;
|
|
1900
|
-
} else {
|
|
1901
|
-
attempts++;
|
|
1902
|
-
if (attempts >= maxRetries) {
|
|
1903
|
-
let messagesHandledByDLQ = 0;
|
|
1904
|
-
let messagesWithoutDLQ = 0;
|
|
1905
|
-
const dlqErrors = [];
|
|
1906
|
-
for (const failedMessage of currentMessages) {
|
|
1907
|
-
const dlqTopic = failedMessage.dlq;
|
|
1908
|
-
if (dlqTopic && failedMessage.originalValue) {
|
|
1909
|
-
const dlqTopicName = dlqTopic.name;
|
|
1910
|
-
const deadLetterRecord = {
|
|
1911
|
-
originalRecord: {
|
|
1912
|
-
...failedMessage.originalValue,
|
|
1913
|
-
// Include original Kafka message metadata
|
|
1914
|
-
__sourcePartition: failedMessage.originalMessage.partition,
|
|
1915
|
-
__sourceOffset: failedMessage.originalMessage.offset,
|
|
1916
|
-
__sourceTimestamp: failedMessage.originalMessage.timestamp
|
|
1917
|
-
},
|
|
1918
|
-
errorMessage: error instanceof Error ? error.message : String(error),
|
|
1919
|
-
errorType: error instanceof Error ? error.constructor.name : "Unknown",
|
|
1920
|
-
failedAt: /* @__PURE__ */ new Date(),
|
|
1921
|
-
source: "transform"
|
|
1922
|
-
};
|
|
1923
|
-
cliLog({
|
|
1924
|
-
action: "DeadLetter",
|
|
1925
|
-
message: `Sending failed message to DLQ ${dlqTopicName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
1926
|
-
message_type: "Error"
|
|
1927
|
-
});
|
|
1928
|
-
try {
|
|
1929
|
-
await producer.send({
|
|
1930
|
-
topic: dlqTopicName,
|
|
1931
|
-
messages: [{ value: JSON.stringify(deadLetterRecord) }]
|
|
1932
|
-
});
|
|
1933
|
-
logger2.log(`Sent failed message to DLQ ${dlqTopicName}`);
|
|
1934
|
-
messagesHandledByDLQ++;
|
|
1935
|
-
} catch (dlqError) {
|
|
1936
|
-
const errorMsg = `Failed to send message to DLQ: ${dlqError}`;
|
|
1937
|
-
logger2.error(errorMsg);
|
|
1938
|
-
dlqErrors.push(errorMsg);
|
|
1939
|
-
}
|
|
1940
|
-
} else if (!dlqTopic) {
|
|
1941
|
-
messagesWithoutDLQ++;
|
|
1942
|
-
logger2.warn(
|
|
1943
|
-
`Cannot send to DLQ: no DLQ configured for message (batch has mixed DLQ configurations)`
|
|
1944
|
-
);
|
|
1945
|
-
} else {
|
|
1946
|
-
messagesWithoutDLQ++;
|
|
1947
|
-
logger2.warn(
|
|
1948
|
-
`Cannot send to DLQ: original message value not available`
|
|
1949
|
-
);
|
|
1950
|
-
}
|
|
1951
|
-
}
|
|
1952
|
-
const allMessagesHandled = messagesHandledByDLQ === currentMessages.length && messagesWithoutDLQ === 0 && dlqErrors.length === 0;
|
|
1953
|
-
if (allMessagesHandled) {
|
|
1954
|
-
logger2.log(
|
|
1955
|
-
`All ${messagesHandledByDLQ} failed message(s) sent to DLQ, not throwing original error`
|
|
1956
|
-
);
|
|
1957
|
-
return;
|
|
1958
|
-
}
|
|
1959
|
-
if (messagesWithoutDLQ > 0) {
|
|
1960
|
-
logger2.error(
|
|
1961
|
-
`Cannot handle batch failure: ${messagesWithoutDLQ} message(s) have no DLQ configured`
|
|
1962
|
-
);
|
|
1963
|
-
}
|
|
1964
|
-
if (dlqErrors.length > 0) {
|
|
1965
|
-
logger2.error(
|
|
1966
|
-
`Some messages failed to send to DLQ: ${dlqErrors.join(", ")}`
|
|
1967
|
-
);
|
|
1968
|
-
}
|
|
1969
|
-
if (messagesHandledByDLQ > 0) {
|
|
1970
|
-
logger2.warn(
|
|
1971
|
-
`Partial DLQ success: ${messagesHandledByDLQ}/${currentMessages.length} message(s) sent to DLQ, but throwing due to incomplete batch handling`
|
|
1972
|
-
);
|
|
1973
|
-
}
|
|
1974
|
-
throw error;
|
|
1975
|
-
}
|
|
1976
|
-
logger2.warn(
|
|
1977
|
-
`Send ${currentMessages.length} messages failed (attempt ${attempts}/${maxRetries}), retrying: ${error}`
|
|
1978
|
-
);
|
|
1979
|
-
await new Promise((resolve2) => setTimeout(resolve2, 100 * attempts));
|
|
1980
|
-
}
|
|
1981
|
-
}
|
|
1982
|
-
}
|
|
1983
|
-
};
|
|
1984
1835
|
var MAX_STREAMING_CONCURRENCY = process3.env.MAX_STREAMING_CONCURRENCY ? parseInt(process3.env.MAX_STREAMING_CONCURRENCY, 10) : DEFAULT_MAX_STREAMING_CONCURRENCY;
|
|
1985
1836
|
var metricsLog = (log) => {
|
|
1986
1837
|
const req = http3.request({
|
|
@@ -2126,57 +1977,95 @@ var handleMessage = async (logger2, streamingFunctionWithConfigList, message, pr
|
|
|
2126
1977
|
}
|
|
2127
1978
|
return void 0;
|
|
2128
1979
|
};
|
|
2129
|
-
var
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
const
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
}
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
1980
|
+
var handleDLQForFailedMessages = async (logger2, producer, messages, error) => {
|
|
1981
|
+
let messagesHandledByDLQ = 0;
|
|
1982
|
+
let messagesWithoutDLQ = 0;
|
|
1983
|
+
let dlqErrors = 0;
|
|
1984
|
+
for (const msg of messages) {
|
|
1985
|
+
if (msg.dlq && msg.originalValue) {
|
|
1986
|
+
const deadLetterRecord = {
|
|
1987
|
+
originalRecord: {
|
|
1988
|
+
...msg.originalValue,
|
|
1989
|
+
// Include original Kafka message metadata
|
|
1990
|
+
__sourcePartition: msg.originalMessage.partition,
|
|
1991
|
+
__sourceOffset: msg.originalMessage.offset,
|
|
1992
|
+
__sourceTimestamp: msg.originalMessage.timestamp
|
|
1993
|
+
},
|
|
1994
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
1995
|
+
errorType: error instanceof Error ? error.constructor.name : "Unknown",
|
|
1996
|
+
failedAt: /* @__PURE__ */ new Date(),
|
|
1997
|
+
source: "transform"
|
|
1998
|
+
};
|
|
1999
|
+
cliLog({
|
|
2000
|
+
action: "DeadLetter",
|
|
2001
|
+
message: `Sending failed message to DLQ ${msg.dlq.name}: ${error instanceof Error ? error.message : String(error)}`,
|
|
2002
|
+
message_type: "Error"
|
|
2003
|
+
});
|
|
2004
|
+
try {
|
|
2005
|
+
await producer.send({
|
|
2006
|
+
topic: msg.dlq.name,
|
|
2007
|
+
messages: [{ value: JSON.stringify(deadLetterRecord) }]
|
|
2008
|
+
});
|
|
2009
|
+
logger2.log(`Sent failed message to DLQ ${msg.dlq.name}`);
|
|
2010
|
+
messagesHandledByDLQ++;
|
|
2011
|
+
} catch (dlqError) {
|
|
2012
|
+
logger2.error(`Failed to send to DLQ: ${dlqError}`);
|
|
2013
|
+
dlqErrors++;
|
|
2156
2014
|
}
|
|
2015
|
+
} else if (!msg.dlq) {
|
|
2016
|
+
messagesWithoutDLQ++;
|
|
2017
|
+
logger2.warn(`Cannot send to DLQ: no DLQ configured for message`);
|
|
2018
|
+
} else {
|
|
2019
|
+
messagesWithoutDLQ++;
|
|
2020
|
+
logger2.warn(`Cannot send to DLQ: original message value not available`);
|
|
2157
2021
|
}
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
)
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
`Sent final ${chunk.length} transformed data to ${targetTopic.name}`
|
|
2022
|
+
}
|
|
2023
|
+
const allMessagesHandled = messagesHandledByDLQ === messages.length && messagesWithoutDLQ === 0 && dlqErrors === 0;
|
|
2024
|
+
if (allMessagesHandled) {
|
|
2025
|
+
logger2.log(
|
|
2026
|
+
`All ${messagesHandledByDLQ} failed message(s) sent to DLQ, suppressing original error`
|
|
2027
|
+
);
|
|
2028
|
+
} else if (messagesHandledByDLQ > 0) {
|
|
2029
|
+
logger2.warn(
|
|
2030
|
+
`Partial DLQ success: ${messagesHandledByDLQ}/${messages.length} message(s) sent to DLQ`
|
|
2031
|
+
);
|
|
2032
|
+
if (messagesWithoutDLQ > 0) {
|
|
2033
|
+
logger2.error(
|
|
2034
|
+
`Cannot handle batch failure: ${messagesWithoutDLQ} message(s) have no DLQ configured or missing original value`
|
|
2172
2035
|
);
|
|
2173
2036
|
}
|
|
2037
|
+
if (dlqErrors > 0) {
|
|
2038
|
+
logger2.error(`${dlqErrors} message(s) failed to send to DLQ`);
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
return allMessagesHandled;
|
|
2042
|
+
};
|
|
2043
|
+
var sendMessages = async (logger2, metrics, targetTopic, producer, messages) => {
|
|
2044
|
+
if (messages.length === 0) return;
|
|
2045
|
+
for (const msg of messages) {
|
|
2046
|
+
metrics.bytes += import_node_buffer.Buffer.byteLength(msg.value, "utf8");
|
|
2047
|
+
}
|
|
2048
|
+
metrics.count_out += messages.length;
|
|
2049
|
+
try {
|
|
2050
|
+
await producer.send({
|
|
2051
|
+
topic: targetTopic.name,
|
|
2052
|
+
messages
|
|
2053
|
+
});
|
|
2054
|
+
logger2.log(`Sent ${messages.length} messages to ${targetTopic.name}`);
|
|
2174
2055
|
} catch (e) {
|
|
2175
2056
|
logger2.error(`Failed to send transformed data`);
|
|
2176
2057
|
if (e instanceof Error) {
|
|
2177
2058
|
logError(logger2, e);
|
|
2178
2059
|
}
|
|
2179
|
-
|
|
2060
|
+
const allHandledByDLQ = await handleDLQForFailedMessages(
|
|
2061
|
+
logger2,
|
|
2062
|
+
producer,
|
|
2063
|
+
messages,
|
|
2064
|
+
e
|
|
2065
|
+
);
|
|
2066
|
+
if (!allHandledByDLQ) {
|
|
2067
|
+
throw e;
|
|
2068
|
+
}
|
|
2180
2069
|
}
|
|
2181
2070
|
};
|
|
2182
2071
|
var sendMessageMetrics = (logger2, metrics) => {
|
|
@@ -2418,16 +2307,10 @@ var runStreamingFunctions = async (args) => {
|
|
|
2418
2307
|
fromBeginning: true
|
|
2419
2308
|
}
|
|
2420
2309
|
});
|
|
2421
|
-
const
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
retry: {
|
|
2426
|
-
retries: MAX_RETRIES_PRODUCER,
|
|
2427
|
-
maxRetryTime: MAX_RETRY_TIME_MS
|
|
2428
|
-
}
|
|
2429
|
-
}
|
|
2430
|
-
});
|
|
2310
|
+
const maxMessageBytes = args.targetTopic?.max_message_bytes || 1024 * 1024;
|
|
2311
|
+
const producer = kafka.producer(
|
|
2312
|
+
createProducerConfig(maxMessageBytes)
|
|
2313
|
+
);
|
|
2431
2314
|
try {
|
|
2432
2315
|
logger2.log("Starting producer...");
|
|
2433
2316
|
await startProducer(logger2, producer);
|