@514labs/moose-lib 0.6.276-ci-1-gfe86cd2c → 0.6.276-ci-3-g7a7bb18a

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.
@@ -13,11 +13,7 @@ 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 {
17
- KafkaConsumer,
18
- KafkaJS,
19
- CODES
20
- } from "@confluentinc/kafka-javascript";
16
+ import { KafkaJS } from "@514labs/kafka-javascript";
21
17
  function isTruthy(value) {
22
18
  if (!value) return false;
23
19
  switch (value.trim().toLowerCase()) {
@@ -46,7 +42,7 @@ function createProducerConfig(maxMessageBytes) {
46
42
  ...maxMessageBytes && { "message.max.bytes": maxMessageBytes }
47
43
  };
48
44
  }
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;
45
+ var Kafka, compilerLog, getClickhouseClient, cliLog, MAX_RETRIES, MAX_RETRY_TIME_MS, RETRY_INITIAL_TIME_MS, MAX_RETRIES_PRODUCER, ACKs, parseBrokerString, logError, buildSaslConfig, getKafkaClient;
50
46
  var init_commons = __esm({
51
47
  "src/commons.ts"() {
52
48
  "use strict";
@@ -140,59 +136,6 @@ var init_commons = __esm({
140
136
  }
141
137
  });
142
138
  };
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
- };
196
139
  }
197
140
  });
198
141
 
@@ -1916,13 +1859,15 @@ var runBlocks = async (config) => {
1916
1859
  // src/streaming-functions/runner.ts
1917
1860
  init_commons();
1918
1861
  import { Readable as Readable2 } from "stream";
1919
- import { KafkaJS as KafkaJS2, CODES as CODES2 } from "@confluentinc/kafka-javascript";
1862
+ import { KafkaJS as KafkaJS2 } from "@514labs/kafka-javascript";
1920
1863
  import { Buffer as Buffer2 } from "buffer";
1921
1864
  import * as process3 from "process";
1922
1865
  import * as http3 from "http";
1923
1866
  var { Kafka: Kafka2 } = KafkaJS2;
1924
1867
  var HOSTNAME = process3.env.HOSTNAME;
1925
1868
  var AUTO_COMMIT_INTERVAL_MS = 5e3;
1869
+ var PARTITIONS_CONSUMED_CONCURRENTLY = 3;
1870
+ var MAX_RETRIES_CONSUMER = 150;
1926
1871
  var SESSION_TIMEOUT_CONSUMER = 3e4;
1927
1872
  var HEARTBEAT_INTERVAL_CONSUMER = 3e3;
1928
1873
  var DEFAULT_MAX_STREAMING_CONCURRENCY = 100;
@@ -1963,31 +1908,23 @@ var stopProducer = async (logger2, producer) => {
1963
1908
  var stopConsumer = async (logger2, consumer, sourceTopic) => {
1964
1909
  try {
1965
1910
  logger2.log("Pausing consumer...");
1966
- const topicPartitions = Array.from(
1911
+ const partitionNumbers = Array.from(
1967
1912
  { length: sourceTopic.partitions },
1968
- (_, i) => ({
1969
- topic: sourceTopic.name,
1970
- partition: i
1971
- })
1913
+ (_, i) => i
1972
1914
  );
1973
- consumer.pause(topicPartitions);
1915
+ await consumer.pause([
1916
+ {
1917
+ topic: sourceTopic.name,
1918
+ partitions: partitionNumbers
1919
+ }
1920
+ ]);
1974
1921
  logger2.log("Disconnecting consumer...");
1975
- await new Promise((resolve2, reject) => {
1976
- consumer.disconnect((err) => {
1977
- if (err) {
1978
- reject(err);
1979
- } else {
1980
- resolve2();
1981
- }
1982
- });
1983
- });
1922
+ await consumer.disconnect();
1984
1923
  logger2.log("Consumer is shutting down...");
1985
1924
  } catch (error) {
1986
1925
  logger2.error(`Error during consumer shutdown: ${error}`);
1987
1926
  try {
1988
- await new Promise((resolve2) => {
1989
- consumer.disconnect(() => resolve2());
1990
- });
1927
+ await consumer.disconnect();
1991
1928
  logger2.log("Consumer disconnected after error");
1992
1929
  } catch (disconnectError) {
1993
1930
  logger2.error(`Failed to disconnect consumer: ${disconnectError}`);
@@ -2227,15 +2164,7 @@ var startConsumer = async (args, logger2, metrics, _parallelism, consumer, produ
2227
2164
  }
2228
2165
  try {
2229
2166
  logger2.log("Connecting consumer...");
2230
- await new Promise((resolve2, reject) => {
2231
- consumer.connect({}, (err) => {
2232
- if (err) {
2233
- reject(err);
2234
- } else {
2235
- resolve2();
2236
- }
2237
- });
2238
- });
2167
+ await consumer.connect();
2239
2168
  logger2.log("Consumer connected successfully");
2240
2169
  } catch (error) {
2241
2170
  logger2.error("Failed to connect consumer:");
@@ -2260,94 +2189,61 @@ var startConsumer = async (args, logger2, metrics, _parallelism, consumer, produ
2260
2189
  streamingFunctions = [[loadStreamingFunction(args.functionFilePath), {}]];
2261
2190
  fieldMutations = void 0;
2262
2191
  }
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
- });
2278
- }
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
2192
+ await consumer.subscribe({
2193
+ topics: [args.sourceTopic.name]
2194
+ // Use full topic name for Kafka operations
2195
+ });
2196
+ await consumer.run({
2197
+ eachBatchAutoResolve: true,
2198
+ // Enable parallel processing of partitions
2199
+ partitionsConsumedConcurrently: PARTITIONS_CONSUMED_CONCURRENTLY,
2200
+ // To be adjusted
2201
+ eachBatch: async ({ batch, heartbeat, isRunning, isStale }) => {
2202
+ if (!isRunning() || isStale()) {
2203
+ return;
2204
+ }
2205
+ metrics.count_in += batch.messages.length;
2206
+ cliLog({
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();
2310
2218
  }
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(
2219
+ return handleMessage(
2318
2220
  logger2,
2319
- metrics,
2320
- args.targetTopic,
2221
+ streamingFunctions,
2222
+ message,
2321
2223
  producer,
2322
- filteredMessages
2224
+ fieldMutations
2323
2225
  );
2226
+ },
2227
+ {
2228
+ concurrency: MAX_STREAMING_CONCURRENCY
2324
2229
  }
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));
2230
+ ).toArray();
2231
+ const filteredMessages = processedMessages.flat().filter((msg) => msg !== void 0 && msg.value !== void 0);
2232
+ if (args.targetTopic === void 0 || processedMessages.length === 0) {
2233
+ return;
2234
+ }
2235
+ await heartbeat();
2236
+ if (filteredMessages.length > 0) {
2237
+ await sendMessages(
2238
+ logger2,
2239
+ metrics,
2240
+ args.targetTopic,
2241
+ producer,
2242
+ filteredMessages
2243
+ );
2340
2244
  }
2341
2245
  }
2342
- };
2343
- consumeLoop().catch((err) => {
2344
- logger2.error(`Consumer loop crashed: ${err}`);
2345
- isRunning = false;
2346
2246
  });
2347
- consumer._isRunning = isRunning;
2348
- consumer._stopConsuming = () => {
2349
- isRunning = false;
2350
- };
2351
2247
  logger2.log("Consumer is running...");
2352
2248
  };
2353
2249
  var buildLogger = (args, workerId) => {
@@ -2427,33 +2323,6 @@ var runStreamingFunctions = async (args) => {
2427
2323
  setTimeout(() => sendMessageMetrics(logger2, metrics), 1e3);
2428
2324
  const clientIdPrefix = HOSTNAME ? `${HOSTNAME}-` : "";
2429
2325
  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
- );
2457
2326
  const kafka = await getKafkaClient(
2458
2327
  {
2459
2328
  clientId: processId,
@@ -2465,6 +2334,20 @@ var runStreamingFunctions = async (args) => {
2465
2334
  },
2466
2335
  logger2
2467
2336
  );
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
+ });
2468
2351
  const maxMessageBytes = args.targetTopic?.max_message_bytes || 1024 * 1024;
2469
2352
  const producer = kafka.producer(
2470
2353
  createProducerConfig(maxMessageBytes)
@@ -2501,9 +2384,6 @@ var runStreamingFunctions = async (args) => {
2501
2384
  },
2502
2385
  workerStop: async ([logger2, producer, consumer]) => {
2503
2386
  logger2.log(`Received SIGTERM, shutting down gracefully...`);
2504
- if (consumer._stopConsuming) {
2505
- consumer._stopConsuming();
2506
- }
2507
2387
  logger2.log("Stopping consumer first...");
2508
2388
  await stopConsumer(logger2, consumer, args.sourceTopic);
2509
2389
  logger2.log("Waiting for in-flight messages to complete...");