@514labs/moose-lib 0.6.276-ci-6-g278c5539 → 0.6.276-ci-1-gfe86cd2c
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.js +57 -1
- package/dist/browserCompatible.js.map +1 -1
- package/dist/browserCompatible.mjs +62 -2
- package/dist/browserCompatible.mjs.map +1 -1
- package/dist/compilerPlugin.js.map +1 -1
- package/dist/compilerPlugin.mjs +5 -1
- package/dist/compilerPlugin.mjs.map +1 -1
- package/dist/dmv2/index.js +57 -1
- package/dist/dmv2/index.js.map +1 -1
- package/dist/dmv2/index.mjs +62 -2
- package/dist/dmv2/index.mjs.map +1 -1
- package/dist/index.d.mts +27 -2
- package/dist/index.d.ts +27 -2
- package/dist/index.js +63 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +65 -2
- package/dist/index.mjs.map +1 -1
- package/dist/moose-runner.js +191 -75
- package/dist/moose-runner.js.map +1 -1
- package/dist/moose-runner.mjs +197 -77
- package/dist/moose-runner.mjs.map +1 -1
- package/package.json +1 -1
package/dist/moose-runner.mjs
CHANGED
|
@@ -13,7 +13,11 @@ var __esm = (fn, res) => function __init() {
|
|
|
13
13
|
// src/commons.ts
|
|
14
14
|
import http from "http";
|
|
15
15
|
import { createClient } from "@clickhouse/client";
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
KafkaConsumer,
|
|
18
|
+
KafkaJS,
|
|
19
|
+
CODES
|
|
20
|
+
} from "@confluentinc/kafka-javascript";
|
|
17
21
|
function isTruthy(value) {
|
|
18
22
|
if (!value) return false;
|
|
19
23
|
switch (value.trim().toLowerCase()) {
|
|
@@ -42,7 +46,7 @@ function createProducerConfig(maxMessageBytes) {
|
|
|
42
46
|
...maxMessageBytes && { "message.max.bytes": maxMessageBytes }
|
|
43
47
|
};
|
|
44
48
|
}
|
|
45
|
-
var Kafka, compilerLog, getClickhouseClient, cliLog, MAX_RETRIES, MAX_RETRY_TIME_MS, RETRY_INITIAL_TIME_MS, MAX_RETRIES_PRODUCER, ACKs, parseBrokerString, logError, buildSaslConfig, getKafkaClient;
|
|
49
|
+
var Kafka, compilerLog, getClickhouseClient, cliLog, MAX_RETRIES, MAX_RETRY_TIME_MS, RETRY_INITIAL_TIME_MS, MAX_RETRIES_PRODUCER, ACKs, parseBrokerString, logError, buildSaslConfig, getKafkaClient, buildNativeSaslConfig, createNativeKafkaConsumer;
|
|
46
50
|
var init_commons = __esm({
|
|
47
51
|
"src/commons.ts"() {
|
|
48
52
|
"use strict";
|
|
@@ -136,6 +140,59 @@ var init_commons = __esm({
|
|
|
136
140
|
}
|
|
137
141
|
});
|
|
138
142
|
};
|
|
143
|
+
buildNativeSaslConfig = (logger2, cfg) => {
|
|
144
|
+
if (!cfg.saslMechanism || !cfg.saslUsername || !cfg.saslPassword) {
|
|
145
|
+
return {};
|
|
146
|
+
}
|
|
147
|
+
const mechanism = cfg.saslMechanism.toUpperCase();
|
|
148
|
+
const validMechanisms = ["PLAIN", "SCRAM-SHA-256", "SCRAM-SHA-512"];
|
|
149
|
+
if (!validMechanisms.includes(mechanism)) {
|
|
150
|
+
logger2.warn(`Unsupported SASL mechanism: ${cfg.saslMechanism}`);
|
|
151
|
+
return {};
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
"sasl.mechanisms": mechanism,
|
|
155
|
+
"sasl.username": cfg.saslUsername,
|
|
156
|
+
"sasl.password": cfg.saslPassword
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
createNativeKafkaConsumer = (cfg, logger2, rebalanceCb) => {
|
|
160
|
+
const brokers = parseBrokerString(cfg.broker || "");
|
|
161
|
+
if (brokers.length === 0) {
|
|
162
|
+
throw new Error(`No valid broker addresses found in: "${cfg.broker}"`);
|
|
163
|
+
}
|
|
164
|
+
logger2.log(
|
|
165
|
+
`Creating native KafkaConsumer with brokers: ${brokers.join(", ")}`
|
|
166
|
+
);
|
|
167
|
+
logger2.log(`Security protocol: ${cfg.securityProtocol || "plaintext"}`);
|
|
168
|
+
logger2.log(`Client ID: ${cfg.clientId}`);
|
|
169
|
+
logger2.log(`Group ID: ${cfg.groupId}`);
|
|
170
|
+
const saslConfig = buildNativeSaslConfig(logger2, cfg);
|
|
171
|
+
const consumerConfig = {
|
|
172
|
+
// Connection
|
|
173
|
+
"bootstrap.servers": brokers.join(","),
|
|
174
|
+
"client.id": cfg.clientId,
|
|
175
|
+
// Group management
|
|
176
|
+
"group.id": cfg.groupId,
|
|
177
|
+
"session.timeout.ms": cfg.sessionTimeoutMs ?? 3e4,
|
|
178
|
+
"heartbeat.interval.ms": cfg.heartbeatIntervalMs ?? 3e3,
|
|
179
|
+
"max.poll.interval.ms": cfg.maxPollIntervalMs ?? 3e5,
|
|
180
|
+
// Offset management
|
|
181
|
+
"enable.auto.commit": cfg.autoCommit ?? true,
|
|
182
|
+
"auto.commit.interval.ms": cfg.autoCommitIntervalMs ?? 5e3,
|
|
183
|
+
// Security
|
|
184
|
+
...cfg.securityProtocol === "SASL_SSL" && {
|
|
185
|
+
"security.protocol": "sasl_ssl"
|
|
186
|
+
},
|
|
187
|
+
...saslConfig,
|
|
188
|
+
// Rebalance callback
|
|
189
|
+
...rebalanceCb && { rebalance_cb: rebalanceCb }
|
|
190
|
+
};
|
|
191
|
+
const topicConfig = {
|
|
192
|
+
"auto.offset.reset": cfg.autoOffsetReset ?? "earliest"
|
|
193
|
+
};
|
|
194
|
+
return new KafkaConsumer(consumerConfig, topicConfig);
|
|
195
|
+
};
|
|
139
196
|
}
|
|
140
197
|
});
|
|
141
198
|
|
|
@@ -1859,15 +1916,13 @@ var runBlocks = async (config) => {
|
|
|
1859
1916
|
// src/streaming-functions/runner.ts
|
|
1860
1917
|
init_commons();
|
|
1861
1918
|
import { Readable as Readable2 } from "stream";
|
|
1862
|
-
import { KafkaJS as KafkaJS2 } from "@confluentinc/kafka-javascript";
|
|
1919
|
+
import { KafkaJS as KafkaJS2, CODES as CODES2 } from "@confluentinc/kafka-javascript";
|
|
1863
1920
|
import { Buffer as Buffer2 } from "buffer";
|
|
1864
1921
|
import * as process3 from "process";
|
|
1865
1922
|
import * as http3 from "http";
|
|
1866
1923
|
var { Kafka: Kafka2 } = KafkaJS2;
|
|
1867
1924
|
var HOSTNAME = process3.env.HOSTNAME;
|
|
1868
1925
|
var AUTO_COMMIT_INTERVAL_MS = 5e3;
|
|
1869
|
-
var PARTITIONS_CONSUMED_CONCURRENTLY = 3;
|
|
1870
|
-
var MAX_RETRIES_CONSUMER = 150;
|
|
1871
1926
|
var SESSION_TIMEOUT_CONSUMER = 3e4;
|
|
1872
1927
|
var HEARTBEAT_INTERVAL_CONSUMER = 3e3;
|
|
1873
1928
|
var DEFAULT_MAX_STREAMING_CONCURRENCY = 100;
|
|
@@ -1908,23 +1963,31 @@ var stopProducer = async (logger2, producer) => {
|
|
|
1908
1963
|
var stopConsumer = async (logger2, consumer, sourceTopic) => {
|
|
1909
1964
|
try {
|
|
1910
1965
|
logger2.log("Pausing consumer...");
|
|
1911
|
-
const
|
|
1966
|
+
const topicPartitions = Array.from(
|
|
1912
1967
|
{ length: sourceTopic.partitions },
|
|
1913
|
-
(_, i) =>
|
|
1914
|
-
);
|
|
1915
|
-
await consumer.pause([
|
|
1916
|
-
{
|
|
1968
|
+
(_, i) => ({
|
|
1917
1969
|
topic: sourceTopic.name,
|
|
1918
|
-
|
|
1919
|
-
}
|
|
1920
|
-
|
|
1970
|
+
partition: i
|
|
1971
|
+
})
|
|
1972
|
+
);
|
|
1973
|
+
consumer.pause(topicPartitions);
|
|
1921
1974
|
logger2.log("Disconnecting consumer...");
|
|
1922
|
-
await
|
|
1975
|
+
await new Promise((resolve2, reject) => {
|
|
1976
|
+
consumer.disconnect((err) => {
|
|
1977
|
+
if (err) {
|
|
1978
|
+
reject(err);
|
|
1979
|
+
} else {
|
|
1980
|
+
resolve2();
|
|
1981
|
+
}
|
|
1982
|
+
});
|
|
1983
|
+
});
|
|
1923
1984
|
logger2.log("Consumer is shutting down...");
|
|
1924
1985
|
} catch (error) {
|
|
1925
1986
|
logger2.error(`Error during consumer shutdown: ${error}`);
|
|
1926
1987
|
try {
|
|
1927
|
-
await
|
|
1988
|
+
await new Promise((resolve2) => {
|
|
1989
|
+
consumer.disconnect(() => resolve2());
|
|
1990
|
+
});
|
|
1928
1991
|
logger2.log("Consumer disconnected after error");
|
|
1929
1992
|
} catch (disconnectError) {
|
|
1930
1993
|
logger2.error(`Failed to disconnect consumer: ${disconnectError}`);
|
|
@@ -2164,7 +2227,15 @@ var startConsumer = async (args, logger2, metrics, _parallelism, consumer, produ
|
|
|
2164
2227
|
}
|
|
2165
2228
|
try {
|
|
2166
2229
|
logger2.log("Connecting consumer...");
|
|
2167
|
-
await
|
|
2230
|
+
await new Promise((resolve2, reject) => {
|
|
2231
|
+
consumer.connect({}, (err) => {
|
|
2232
|
+
if (err) {
|
|
2233
|
+
reject(err);
|
|
2234
|
+
} else {
|
|
2235
|
+
resolve2();
|
|
2236
|
+
}
|
|
2237
|
+
});
|
|
2238
|
+
});
|
|
2168
2239
|
logger2.log("Consumer connected successfully");
|
|
2169
2240
|
} catch (error) {
|
|
2170
2241
|
logger2.error("Failed to connect consumer:");
|
|
@@ -2189,61 +2260,94 @@ var startConsumer = async (args, logger2, metrics, _parallelism, consumer, produ
|
|
|
2189
2260
|
streamingFunctions = [[loadStreamingFunction(args.functionFilePath), {}]];
|
|
2190
2261
|
fieldMutations = void 0;
|
|
2191
2262
|
}
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
action: "Received",
|
|
2208
|
-
message: `${logger2.logPrefix} ${batch.messages.length} message(s)`
|
|
2209
|
-
});
|
|
2210
|
-
logger2.log(`Received ${batch.messages.length} message(s)`);
|
|
2211
|
-
let index = 0;
|
|
2212
|
-
const readableStream = Readable2.from(batch.messages);
|
|
2213
|
-
const processedMessages = await readableStream.map(
|
|
2214
|
-
async (message) => {
|
|
2215
|
-
index++;
|
|
2216
|
-
if (batch.messages.length > DEFAULT_MAX_STREAMING_CONCURRENCY && index % DEFAULT_MAX_STREAMING_CONCURRENCY || index - 1 === batch.messages.length) {
|
|
2217
|
-
await heartbeat();
|
|
2263
|
+
consumer.subscribe([args.sourceTopic.name]);
|
|
2264
|
+
consumer.setDefaultConsumeTimeout(1e3);
|
|
2265
|
+
let isRunning = true;
|
|
2266
|
+
const consumeLoop = async () => {
|
|
2267
|
+
while (isRunning && consumer.isConnected()) {
|
|
2268
|
+
try {
|
|
2269
|
+
const messages = await new Promise(
|
|
2270
|
+
(resolve2, reject) => {
|
|
2271
|
+
consumer.consume(CONSUMER_MAX_BATCH_SIZE, (err, messages2) => {
|
|
2272
|
+
if (err) {
|
|
2273
|
+
reject(err);
|
|
2274
|
+
} else {
|
|
2275
|
+
resolve2(messages2 || []);
|
|
2276
|
+
}
|
|
2277
|
+
});
|
|
2218
2278
|
}
|
|
2219
|
-
|
|
2279
|
+
);
|
|
2280
|
+
if (messages.length === 0) {
|
|
2281
|
+
continue;
|
|
2282
|
+
}
|
|
2283
|
+
metrics.count_in += messages.length;
|
|
2284
|
+
cliLog({
|
|
2285
|
+
action: "Received",
|
|
2286
|
+
message: `${logger2.logPrefix} ${messages.length} message(s)`
|
|
2287
|
+
});
|
|
2288
|
+
logger2.log(`Received ${messages.length} message(s)`);
|
|
2289
|
+
const readableStream = Readable2.from(messages);
|
|
2290
|
+
const processedMessages = await readableStream.map(
|
|
2291
|
+
async (message) => {
|
|
2292
|
+
const kafkaMessage = {
|
|
2293
|
+
value: message.value,
|
|
2294
|
+
key: message.key,
|
|
2295
|
+
partition: message.partition,
|
|
2296
|
+
offset: message.offset,
|
|
2297
|
+
timestamp: message.timestamp,
|
|
2298
|
+
headers: message.headers
|
|
2299
|
+
};
|
|
2300
|
+
return handleMessage(
|
|
2301
|
+
logger2,
|
|
2302
|
+
streamingFunctions,
|
|
2303
|
+
kafkaMessage,
|
|
2304
|
+
producer,
|
|
2305
|
+
fieldMutations
|
|
2306
|
+
);
|
|
2307
|
+
},
|
|
2308
|
+
{
|
|
2309
|
+
concurrency: MAX_STREAMING_CONCURRENCY
|
|
2310
|
+
}
|
|
2311
|
+
).toArray();
|
|
2312
|
+
const filteredMessages = processedMessages.flat().filter((msg) => msg !== void 0 && msg.value !== void 0);
|
|
2313
|
+
if (args.targetTopic === void 0 || processedMessages.length === 0) {
|
|
2314
|
+
continue;
|
|
2315
|
+
}
|
|
2316
|
+
if (filteredMessages.length > 0) {
|
|
2317
|
+
await sendMessages(
|
|
2220
2318
|
logger2,
|
|
2221
|
-
|
|
2222
|
-
|
|
2319
|
+
metrics,
|
|
2320
|
+
args.targetTopic,
|
|
2223
2321
|
producer,
|
|
2224
|
-
|
|
2322
|
+
filteredMessages
|
|
2225
2323
|
);
|
|
2226
|
-
},
|
|
2227
|
-
{
|
|
2228
|
-
concurrency: MAX_STREAMING_CONCURRENCY
|
|
2229
2324
|
}
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2325
|
+
} catch (error) {
|
|
2326
|
+
if (error && typeof error === "object" && "code" in error) {
|
|
2327
|
+
const kafkaError = error;
|
|
2328
|
+
if (kafkaError.code === CODES2.ERRORS.ERR__TIMED_OUT) {
|
|
2329
|
+
continue;
|
|
2330
|
+
}
|
|
2331
|
+
if (kafkaError.code === CODES2.ERRORS.ERR__PARTITION_EOF) {
|
|
2332
|
+
continue;
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
logger2.error(`Error consuming messages: ${error}`);
|
|
2336
|
+
if (error instanceof Error) {
|
|
2337
|
+
logError(logger2, error);
|
|
2338
|
+
}
|
|
2339
|
+
await new Promise((resolve2) => setTimeout(resolve2, 100));
|
|
2244
2340
|
}
|
|
2245
2341
|
}
|
|
2342
|
+
};
|
|
2343
|
+
consumeLoop().catch((err) => {
|
|
2344
|
+
logger2.error(`Consumer loop crashed: ${err}`);
|
|
2345
|
+
isRunning = false;
|
|
2246
2346
|
});
|
|
2347
|
+
consumer._isRunning = isRunning;
|
|
2348
|
+
consumer._stopConsuming = () => {
|
|
2349
|
+
isRunning = false;
|
|
2350
|
+
};
|
|
2247
2351
|
logger2.log("Consumer is running...");
|
|
2248
2352
|
};
|
|
2249
2353
|
var buildLogger = (args, workerId) => {
|
|
@@ -2323,6 +2427,33 @@ var runStreamingFunctions = async (args) => {
|
|
|
2323
2427
|
setTimeout(() => sendMessageMetrics(logger2, metrics), 1e3);
|
|
2324
2428
|
const clientIdPrefix = HOSTNAME ? `${HOSTNAME}-` : "";
|
|
2325
2429
|
const processId = `${clientIdPrefix}${streamingFuncId}-ts-${worker.id}`;
|
|
2430
|
+
const consumer = createNativeKafkaConsumer(
|
|
2431
|
+
{
|
|
2432
|
+
clientId: processId,
|
|
2433
|
+
broker: args.broker,
|
|
2434
|
+
groupId: streamingFuncId,
|
|
2435
|
+
securityProtocol: args.securityProtocol,
|
|
2436
|
+
saslUsername: args.saslUsername,
|
|
2437
|
+
saslPassword: args.saslPassword,
|
|
2438
|
+
saslMechanism: args.saslMechanism,
|
|
2439
|
+
sessionTimeoutMs: SESSION_TIMEOUT_CONSUMER,
|
|
2440
|
+
heartbeatIntervalMs: HEARTBEAT_INTERVAL_CONSUMER,
|
|
2441
|
+
autoCommit: true,
|
|
2442
|
+
autoCommitIntervalMs: AUTO_COMMIT_INTERVAL_MS,
|
|
2443
|
+
autoOffsetReset: "earliest",
|
|
2444
|
+
maxBatchSize: CONSUMER_MAX_BATCH_SIZE
|
|
2445
|
+
},
|
|
2446
|
+
logger2,
|
|
2447
|
+
(err, assignments) => {
|
|
2448
|
+
if (err.code === CODES2.ERRORS.ERR__ASSIGN_PARTITIONS) {
|
|
2449
|
+
logger2.log(`Assigned partitions: ${JSON.stringify(assignments)}`);
|
|
2450
|
+
} else if (err.code === CODES2.ERRORS.ERR__REVOKE_PARTITIONS) {
|
|
2451
|
+
logger2.log(`Revoked partitions: ${JSON.stringify(assignments)}`);
|
|
2452
|
+
} else {
|
|
2453
|
+
logger2.error(`Rebalance error: ${err.message}`);
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
);
|
|
2326
2457
|
const kafka = await getKafkaClient(
|
|
2327
2458
|
{
|
|
2328
2459
|
clientId: processId,
|
|
@@ -2334,20 +2465,6 @@ var runStreamingFunctions = async (args) => {
|
|
|
2334
2465
|
},
|
|
2335
2466
|
logger2
|
|
2336
2467
|
);
|
|
2337
|
-
const consumer = kafka.consumer({
|
|
2338
|
-
kafkaJS: {
|
|
2339
|
-
groupId: streamingFuncId,
|
|
2340
|
-
sessionTimeout: SESSION_TIMEOUT_CONSUMER,
|
|
2341
|
-
heartbeatInterval: HEARTBEAT_INTERVAL_CONSUMER,
|
|
2342
|
-
retry: {
|
|
2343
|
-
retries: MAX_RETRIES_CONSUMER
|
|
2344
|
-
},
|
|
2345
|
-
autoCommit: true,
|
|
2346
|
-
autoCommitInterval: AUTO_COMMIT_INTERVAL_MS,
|
|
2347
|
-
fromBeginning: true
|
|
2348
|
-
},
|
|
2349
|
-
"js.consumer.max.batch.size": CONSUMER_MAX_BATCH_SIZE
|
|
2350
|
-
});
|
|
2351
2468
|
const maxMessageBytes = args.targetTopic?.max_message_bytes || 1024 * 1024;
|
|
2352
2469
|
const producer = kafka.producer(
|
|
2353
2470
|
createProducerConfig(maxMessageBytes)
|
|
@@ -2384,6 +2501,9 @@ var runStreamingFunctions = async (args) => {
|
|
|
2384
2501
|
},
|
|
2385
2502
|
workerStop: async ([logger2, producer, consumer]) => {
|
|
2386
2503
|
logger2.log(`Received SIGTERM, shutting down gracefully...`);
|
|
2504
|
+
if (consumer._stopConsuming) {
|
|
2505
|
+
consumer._stopConsuming();
|
|
2506
|
+
}
|
|
2387
2507
|
logger2.log("Stopping consumer first...");
|
|
2388
2508
|
await stopConsumer(logger2, consumer, args.sourceTopic);
|
|
2389
2509
|
logger2.log("Waiting for in-flight messages to complete...");
|