@514labs/moose-lib 0.6.252-ci-3-gf88b2b20 → 0.6.252-ci-5-g3da4ba34
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-CoxWbneN.d.ts → browserCompatible-DT70VlUr.d.ts} +1 -1
- package/dist/{browserCompatible-BTN82akc.d.mts → browserCompatible-jggiyYK1.d.mts} +1 -1
- package/dist/browserCompatible.d.mts +2 -2
- package/dist/browserCompatible.d.ts +2 -2
- package/dist/browserCompatible.js +6 -14
- package/dist/browserCompatible.js.map +1 -1
- package/dist/browserCompatible.mjs +6 -14
- 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 +6 -14
- package/dist/dmv2/index.js.map +1 -1
- package/dist/dmv2/index.mjs +6 -14
- package/dist/dmv2/index.mjs.map +1 -1
- package/dist/{index-CNlTyF6R.d.mts → index-BIeuSuej.d.mts} +34 -1
- package/dist/{index-CNlTyF6R.d.ts → index-BIeuSuej.d.ts} +34 -1
- package/dist/index.d.mts +5 -28
- package/dist/index.d.ts +5 -28
- package/dist/index.js +7 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -15
- package/dist/index.mjs.map +1 -1
- package/dist/moose-runner.js +217 -100
- package/dist/moose-runner.js.map +1 -1
- package/dist/moose-runner.mjs +217 -100
- package/dist/moose-runner.mjs.map +1 -1
- package/package.json +1 -1
package/dist/moose-runner.js
CHANGED
|
@@ -39,22 +39,6 @@ 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
|
-
}
|
|
58
42
|
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;
|
|
59
43
|
var init_commons = __esm({
|
|
60
44
|
"src/commons.ts"() {
|
|
@@ -1338,6 +1322,18 @@ function convertIcebergS3EngineConfig(config) {
|
|
|
1338
1322
|
compression: config.compression
|
|
1339
1323
|
};
|
|
1340
1324
|
}
|
|
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
|
+
}
|
|
1341
1337
|
function convertTableConfigToEngineConfig(config) {
|
|
1342
1338
|
const engine = extractEngineValue(config);
|
|
1343
1339
|
const basicConfig = convertBasicEngineConfig(engine, config);
|
|
@@ -1363,6 +1359,9 @@ function convertTableConfigToEngineConfig(config) {
|
|
|
1363
1359
|
if (engine === "IcebergS3" /* IcebergS3 */) {
|
|
1364
1360
|
return convertIcebergS3EngineConfig(config);
|
|
1365
1361
|
}
|
|
1362
|
+
if (engine === "Kafka" /* Kafka */) {
|
|
1363
|
+
return convertKafkaEngineConfig(config);
|
|
1364
|
+
}
|
|
1366
1365
|
return void 0;
|
|
1367
1366
|
}
|
|
1368
1367
|
var toInfraMap = (registry) => {
|
|
@@ -1832,6 +1831,156 @@ var MAX_RETRIES_CONSUMER = 150;
|
|
|
1832
1831
|
var SESSION_TIMEOUT_CONSUMER = 3e4;
|
|
1833
1832
|
var HEARTBEAT_INTERVAL_CONSUMER = 3e3;
|
|
1834
1833
|
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
|
+
};
|
|
1835
1984
|
var MAX_STREAMING_CONCURRENCY = process3.env.MAX_STREAMING_CONCURRENCY ? parseInt(process3.env.MAX_STREAMING_CONCURRENCY, 10) : DEFAULT_MAX_STREAMING_CONCURRENCY;
|
|
1836
1985
|
var metricsLog = (log) => {
|
|
1837
1986
|
const req = http3.request({
|
|
@@ -1977,95 +2126,57 @@ var handleMessage = async (logger2, streamingFunctionWithConfigList, message, pr
|
|
|
1977
2126
|
}
|
|
1978
2127
|
return void 0;
|
|
1979
2128
|
};
|
|
1980
|
-
var
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
const
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
}
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
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++;
|
|
2129
|
+
var sendMessages = async (logger2, metrics, targetTopic, producer, messages) => {
|
|
2130
|
+
try {
|
|
2131
|
+
let chunk = [];
|
|
2132
|
+
let chunkSize = 0;
|
|
2133
|
+
const maxMessageSize = targetTopic.max_message_bytes || 1024 * 1024;
|
|
2134
|
+
for (const message of messages) {
|
|
2135
|
+
const messageSize = import_node_buffer.Buffer.byteLength(message.value, "utf8") + KAFKAJS_BYTE_MESSAGE_OVERHEAD;
|
|
2136
|
+
if (chunkSize + messageSize > maxMessageSize) {
|
|
2137
|
+
logger2.log(
|
|
2138
|
+
`Sending ${chunkSize} bytes of a transformed record batch to ${targetTopic.name}`
|
|
2139
|
+
);
|
|
2140
|
+
await sendChunkWithRetry(
|
|
2141
|
+
logger2,
|
|
2142
|
+
targetTopic,
|
|
2143
|
+
producer,
|
|
2144
|
+
chunk,
|
|
2145
|
+
maxMessageSize
|
|
2146
|
+
);
|
|
2147
|
+
logger2.log(
|
|
2148
|
+
`Sent ${chunk.length} transformed records to ${targetTopic.name}`
|
|
2149
|
+
);
|
|
2150
|
+
chunk = [message];
|
|
2151
|
+
chunkSize = messageSize;
|
|
2152
|
+
} else {
|
|
2153
|
+
chunk.push(message);
|
|
2154
|
+
metrics.bytes += import_node_buffer.Buffer.byteLength(message.value, "utf8");
|
|
2155
|
+
chunkSize += messageSize;
|
|
2014
2156
|
}
|
|
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`);
|
|
2021
2157
|
}
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2158
|
+
metrics.count_out += chunk.length;
|
|
2159
|
+
if (chunk.length > 0) {
|
|
2160
|
+
logger2.log(
|
|
2161
|
+
`Sending ${chunkSize} bytes of a transformed record batch to ${targetTopic.name}`
|
|
2162
|
+
);
|
|
2163
|
+
await sendChunkWithRetry(
|
|
2164
|
+
logger2,
|
|
2165
|
+
targetTopic,
|
|
2166
|
+
producer,
|
|
2167
|
+
chunk,
|
|
2168
|
+
maxMessageSize
|
|
2169
|
+
);
|
|
2170
|
+
logger2.log(
|
|
2171
|
+
`Sent final ${chunk.length} transformed data to ${targetTopic.name}`
|
|
2035
2172
|
);
|
|
2036
2173
|
}
|
|
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
|
-
try {
|
|
2046
|
-
await producer.send({
|
|
2047
|
-
topic: targetTopic.name,
|
|
2048
|
-
messages
|
|
2049
|
-
});
|
|
2050
|
-
for (const msg of messages) {
|
|
2051
|
-
metrics.bytes += import_node_buffer.Buffer.byteLength(msg.value, "utf8");
|
|
2052
|
-
}
|
|
2053
|
-
metrics.count_out += messages.length;
|
|
2054
|
-
logger2.log(`Sent ${messages.length} messages to ${targetTopic.name}`);
|
|
2055
2174
|
} catch (e) {
|
|
2056
2175
|
logger2.error(`Failed to send transformed data`);
|
|
2057
2176
|
if (e instanceof Error) {
|
|
2058
2177
|
logError(logger2, e);
|
|
2059
2178
|
}
|
|
2060
|
-
|
|
2061
|
-
logger2,
|
|
2062
|
-
producer,
|
|
2063
|
-
messages,
|
|
2064
|
-
e
|
|
2065
|
-
);
|
|
2066
|
-
if (!allHandledByDLQ) {
|
|
2067
|
-
throw e;
|
|
2068
|
-
}
|
|
2179
|
+
throw e;
|
|
2069
2180
|
}
|
|
2070
2181
|
};
|
|
2071
2182
|
var sendMessageMetrics = (logger2, metrics) => {
|
|
@@ -2307,10 +2418,16 @@ var runStreamingFunctions = async (args) => {
|
|
|
2307
2418
|
fromBeginning: true
|
|
2308
2419
|
}
|
|
2309
2420
|
});
|
|
2310
|
-
const
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2421
|
+
const producer = kafka.producer({
|
|
2422
|
+
kafkaJS: {
|
|
2423
|
+
idempotent: true,
|
|
2424
|
+
acks: ACKs,
|
|
2425
|
+
retry: {
|
|
2426
|
+
retries: MAX_RETRIES_PRODUCER,
|
|
2427
|
+
maxRetryTime: MAX_RETRY_TIME_MS
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
});
|
|
2314
2431
|
try {
|
|
2315
2432
|
logger2.log("Starting producer...");
|
|
2316
2433
|
await startProducer(logger2, producer);
|