@openfn/ws-worker 1.4.1 → 1.5.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # ws-worker
2
2
 
3
+ ## 1.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - a08fb47: Update CLI docs
8
+ Add WORKER_MAX_SOCKET_TIMEOUT_SECONDS
9
+
10
+ ## 1.5.0
11
+
12
+ ### Minor Changes
13
+
14
+ - f363254: Allow a payload limit to be set for large dataclips and logs (payload_limit_mb)
15
+
3
16
  ## 1.4.1
4
17
 
5
18
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -41,6 +41,7 @@ interface Channel extends Channel$1 {
41
41
 
42
42
  declare type WorkerRunOptions = ExecuteOptions & {
43
43
  outputDataclips?: boolean;
44
+ payloadLimitMb?: number;
44
45
  };
45
46
 
46
47
  declare type Context = {
@@ -64,6 +65,8 @@ declare type ServerOptions = {
64
65
  min?: number;
65
66
  max?: number;
66
67
  };
68
+ socketTimeoutSeconds?: number;
69
+ payloadLimitMb?: number;
67
70
  };
68
71
  interface ServerApp extends Koa {
69
72
  id: string;
package/dist/index.js CHANGED
@@ -29,7 +29,7 @@ var name, version, description, main, type, scripts, bin, author, license, depen
29
29
  var init_package = __esm({
30
30
  "package.json"() {
31
31
  name = "@openfn/ws-worker";
32
- version = "1.4.1";
32
+ version = "1.5.1";
33
33
  description = "A Websocket Worker to connect Lightning to a Runtime Engine";
34
34
  main = "dist/index.js";
35
35
  type = "module";
@@ -167,7 +167,7 @@ var waitForRuns = (app, logger) => new Promise((resolve) => {
167
167
  log();
168
168
  app.events.on(INTERNAL_RUN_COMPLETE, onRunComplete);
169
169
  } else {
170
- logger.debug("No active rns detected");
170
+ logger.debug("No active runs detected, closing immediately");
171
171
  resolve();
172
172
  }
173
173
  });
@@ -242,7 +242,10 @@ var claim = (app, logger = mockLogger, options = {}) => {
242
242
  }
243
243
  logger.debug("requesting run...");
244
244
  app.queueChannel.push(CLAIM, { demand: 1 }).receive("ok", ({ runs }) => {
245
- logger.debug(`pulled ${runs.length} runs`);
245
+ logger.debug(
246
+ `claimed ${runs.length} runs: `,
247
+ runs.map((r) => r.id).join(",")
248
+ );
246
249
  if (!runs?.length) {
247
250
  return reject(new Error("No runs returned"));
248
251
  }
@@ -265,10 +268,10 @@ var claim = (app, logger = mockLogger, options = {}) => {
265
268
  app.execute(run);
266
269
  resolve();
267
270
  });
268
- }).receive("error", () => {
269
- logger.debug("pull err");
271
+ }).receive("error", (e) => {
272
+ logger.error("Error on claim", e);
270
273
  }).receive("timeout", () => {
271
- logger.debug("pull timeout");
274
+ logger.error("TIMEOUT on claim. Runs may be lost.");
272
275
  reject(new Error("timeout"));
273
276
  });
274
277
  });
@@ -332,13 +335,19 @@ var convert_lightning_plan_default = (run) => {
332
335
  const runtimeOpts = {};
333
336
  const engineOpts = {};
334
337
  if (run.options) {
335
- if (run.options.run_timeout_ms) {
338
+ if ("run_timeout_ms" in run.options) {
336
339
  engineOpts.runTimeoutMs = run.options.run_timeout_ms;
337
340
  }
338
- if (run.options.sanitize) {
341
+ if ("payload_limit_mb" in run.options) {
342
+ engineOpts.payloadLimitMb = run.options.payload_limit_mb;
343
+ }
344
+ if ("run_memory_limit_mb" in run.options) {
345
+ engineOpts.memoryLimitMb = run.options.run_memory_limit_mb;
346
+ }
347
+ if ("sanitize" in run.options) {
339
348
  engineOpts.sanitize = run.options.sanitize;
340
349
  }
341
- if (run.options.hasOwnProperty("output_dataclips")) {
350
+ if ("output_dataclips" in run.options) {
342
351
  engineOpts.outputDataclips = run.options.output_dataclips;
343
352
  }
344
353
  }
@@ -527,7 +536,7 @@ ${prefix("worker")}${versions.worker || "unknown"}`;
527
536
  // src/events/run-start.ts
528
537
  init_package();
529
538
  async function onRunStart(context, event) {
530
- const { channel, state } = context;
539
+ const { channel, state, options = {} } = context;
531
540
  const time = (timestamp() - BigInt(1e7)).toString();
532
541
  const versionLogContext = {
533
542
  ...context,
@@ -541,6 +550,14 @@ async function onRunStart(context, event) {
541
550
  ...event.versions
542
551
  };
543
552
  await sendEvent(channel, RUN_START, { versions });
553
+ if ("payloadLimitMb" in options) {
554
+ await onJobLog(versionLogContext, {
555
+ time,
556
+ message: [`Payload limit: ${options.payloadLimitMb}mb`],
557
+ level: "info",
558
+ name: "RTE"
559
+ });
560
+ }
544
561
  const versionMessage = versions_default(versions);
545
562
  await onJobLog(versionLogContext, {
546
563
  time,
@@ -552,6 +569,7 @@ async function onRunStart(context, event) {
552
569
 
553
570
  // src/events/step-complete.ts
554
571
  import crypto3 from "node:crypto";
572
+ import { timestamp as timestamp2 } from "@openfn/logger";
555
573
 
556
574
  // src/api/reasons.ts
557
575
  var calculateJobExitReason = (jobId, state = { data: {} }, error) => {
@@ -586,8 +604,25 @@ var calculateRunExitReason = (state) => {
586
604
  return { reason: "success", error_type: null, error_message: null };
587
605
  };
588
606
 
607
+ // src/util/ensure-payload-size.ts
608
+ var ensure_payload_size_default = (payload, limit_mb) => {
609
+ if (!isNaN(limit_mb)) {
610
+ const limit = limit_mb;
611
+ const size_bytes = Buffer.byteLength(payload, "utf8");
612
+ const size_mb = size_bytes / 1024 / 1024;
613
+ if (size_mb > limit) {
614
+ const e = new Error();
615
+ e.severity = "kill";
616
+ e.name = "PAYLOAD_TOO_LARGE";
617
+ e.message = `The payload exceeded the size limit of ${limit}mb`;
618
+ throw e;
619
+ }
620
+ }
621
+ };
622
+
589
623
  // src/events/step-complete.ts
590
- function onStepComplete({ channel, state, options }, event, error) {
624
+ async function onStepComplete(context, event, error) {
625
+ const { channel, state, options } = context;
591
626
  const dataclipId = crypto3.randomUUID();
592
627
  const step_id = state.activeStep;
593
628
  const job_id = state.activeJob;
@@ -602,26 +637,35 @@ function onStepComplete({ channel, state, options }, event, error) {
602
637
  event.next?.forEach((nextJobId) => {
603
638
  state.inputDataclips[nextJobId] = dataclipId;
604
639
  });
605
- const { reason, error_message, error_type } = calculateJobExitReason(
606
- job_id,
607
- event.state,
608
- error
609
- );
610
- state.reasons[job_id] = { reason, error_message, error_type };
611
640
  const evt = {
612
641
  step_id,
613
642
  job_id,
614
- output_dataclip_id: dataclipId,
615
- reason,
616
- error_message,
617
- error_type,
618
643
  mem: event.mem,
619
644
  duration: event.duration,
620
645
  thread_id: event.threadId
621
646
  };
622
- if (!options || options.outputDataclips !== false) {
623
- evt.output_dataclip = stringify_default(outputState);
647
+ try {
648
+ if (!options || options.outputDataclips !== false) {
649
+ const payload = stringify_default(outputState);
650
+ ensure_payload_size_default(payload, options?.payloadLimitMb);
651
+ evt.output_dataclip = payload;
652
+ }
653
+ evt.output_dataclip_id = dataclipId;
654
+ } catch (e) {
655
+ evt.output_dataclip_error = "DATACLIP_TOO_LARGE";
656
+ const time = (timestamp2() - BigInt(1e7)).toString();
657
+ await onJobLog(context, {
658
+ time,
659
+ message: [
660
+ "Dataclip too large. This dataclip will not be sent back to lighting."
661
+ ],
662
+ level: "info",
663
+ name: "R/T"
664
+ });
624
665
  }
666
+ const reason = calculateJobExitReason(job_id, event.state, error);
667
+ state.reasons[job_id] = reason;
668
+ Object.assign(evt, reason);
625
669
  return sendEvent(channel, STEP_COMPLETE, evt);
626
670
  }
627
671
 
@@ -640,9 +684,9 @@ async function onStepStart(context, event) {
640
684
  }
641
685
 
642
686
  // src/util/log-final-reason.ts
643
- import { timestamp as timestamp2 } from "@openfn/logger";
687
+ import { timestamp as timestamp3 } from "@openfn/logger";
644
688
  var log_final_reason_default = async (context, reason) => {
645
- const time = (timestamp2() - BigInt(1e7)).toString();
689
+ const time = (timestamp3() - BigInt(1e7)).toString();
646
690
  let message = `Run complete with status: ${reason.reason}`;
647
691
  if (reason.reason !== "success") {
648
692
  message += `
@@ -792,11 +836,25 @@ function onJobError(context, event) {
792
836
  return onStepComplete(context, event, event.error);
793
837
  }
794
838
  }
795
- function onJobLog({ channel, state }, event) {
839
+ function onJobLog({ channel, state, options }, event) {
796
840
  const timeInMicroseconds = BigInt(event.time) / BigInt(1e3);
841
+ let message = event.message;
842
+ try {
843
+ if (typeof event.message === "string") {
844
+ ensure_payload_size_default(event.message, options?.payloadLimitMb);
845
+ message = JSON.parse(message);
846
+ } else if (event.message) {
847
+ const payload = stringify_default(event.message);
848
+ ensure_payload_size_default(payload, options?.payloadLimitMb);
849
+ }
850
+ } catch (e) {
851
+ message = [
852
+ `(Log message redacted: exceeds ${options.payloadLimitMb}mb memory limit)`
853
+ ];
854
+ }
797
855
  const log = {
798
856
  run_id: state.plan.id,
799
- message: typeof event.message === "string" ? JSON.parse(event.message) : event.message,
857
+ message,
800
858
  source: event.name,
801
859
  level: event.level,
802
860
  timestamp: timeInMicroseconds.toString()
@@ -887,7 +945,7 @@ var generateWorkerToken = async (secret, workerId, logger) => {
887
945
  var worker_token_default = generateWorkerToken;
888
946
 
889
947
  // src/channels/worker-queue.ts
890
- var connectToWorkerQueue = (endpoint, serverId, secret, logger, SocketConstructor = PhxSocket) => {
948
+ var connectToWorkerQueue = (endpoint, serverId, secret, timeout = 10, logger, SocketConstructor = PhxSocket) => {
891
949
  const events = new EventEmitter();
892
950
  worker_token_default(secret, serverId, logger).then(async (token) => {
893
951
  const pkg = await Promise.resolve().then(() => (init_package(), package_exports));
@@ -898,7 +956,8 @@ var connectToWorkerQueue = (endpoint, serverId, secret, logger, SocketConstructo
898
956
  };
899
957
  const socket = new SocketConstructor(endpoint, {
900
958
  params,
901
- transport: WebSocket
959
+ transport: WebSocket,
960
+ timeout: timeout * 1e3
902
961
  });
903
962
  let didOpen = false;
904
963
  socket.onOpen(() => {
@@ -930,7 +989,7 @@ var connectToWorkerQueue = (endpoint, serverId, secret, logger, SocketConstructo
930
989
  var worker_queue_default = connectToWorkerQueue;
931
990
 
932
991
  // src/server.ts
933
- var DEFAULT_PORT = 1234;
992
+ var DEFAULT_PORT = 2222;
934
993
  var MIN_BACKOFF = 1e3;
935
994
  var MAX_BACKOFF = 1e3 * 30;
936
995
  function connect(app, logger, options = {}) {
@@ -952,13 +1011,12 @@ function connect(app, logger, options = {}) {
952
1011
  options.maxWorkflows
953
1012
  );
954
1013
  } else {
1014
+ const port = app.server?.address().port;
955
1015
  logger.break();
956
- logger.warn("Workloop not starting");
1016
+ logger.warn("Noloop active: workloop has not started");
957
1017
  logger.info("This server will not auto-pull work from lightning.");
958
1018
  logger.info("You can manually claim by posting to /claim, eg:");
959
- logger.info(
960
- ` curl -X POST http://locahost:${options.port || DEFAULT_PORT}/claim`
961
- );
1019
+ logger.info(` curl -X POST http://localhost:${port}/claim`);
962
1020
  logger.break();
963
1021
  }
964
1022
  };
@@ -982,7 +1040,13 @@ function connect(app, logger, options = {}) {
982
1040
  );
983
1041
  logger.debug(e);
984
1042
  };
985
- worker_queue_default(options.lightning, app.id, options.secret, logger).on("connect", onConnect).on("disconnect", onDisconnect).on("error", onError);
1043
+ worker_queue_default(
1044
+ options.lightning,
1045
+ app.id,
1046
+ options.secret,
1047
+ options.socketTimeoutSeconds,
1048
+ logger
1049
+ ).on("connect", onConnect).on("disconnect", onDisconnect).on("error", onError);
986
1050
  }
987
1051
  function createServer(engine, options = {}) {
988
1052
  const logger = options.logger || createMockLogger2();
@@ -1005,16 +1069,19 @@ function createServer(engine, options = {}) {
1005
1069
  process.send?.("READY");
1006
1070
  router.get("/livez", healthcheck_default);
1007
1071
  router.get("/", healthcheck_default);
1008
- app.options = options || {};
1072
+ app.options = options;
1009
1073
  app.execute = async ({ id, token }) => {
1010
1074
  if (app.socket) {
1011
1075
  app.workflows[id] = true;
1012
1076
  const {
1013
1077
  channel: runChannel,
1014
1078
  plan,
1015
- options: options2,
1079
+ options: options2 = {},
1016
1080
  input
1017
1081
  } = await run_default(app.socket, token, id, logger);
1082
+ if (!("payloadLimitMb" in options2)) {
1083
+ options2.payloadLimitMb = app.options.payloadLimitMb;
1084
+ }
1018
1085
  const onFinish = () => {
1019
1086
  logger.debug(`workflow ${id} complete: releasing worker`);
1020
1087
  delete app.workflows[id];
package/dist/start.js CHANGED
@@ -37,7 +37,7 @@ var name, version, description, main, type, scripts, bin, author, license, depen
37
37
  var init_package = __esm({
38
38
  "package.json"() {
39
39
  name = "@openfn/ws-worker";
40
- version = "1.4.1";
40
+ version = "1.5.1";
41
41
  description = "A Websocket Worker to connect Lightning to a Runtime Engine";
42
42
  main = "dist/index.js";
43
43
  type = "module";
@@ -306,7 +306,7 @@ var waitForRuns = (app, logger2) => new Promise((resolve5) => {
306
306
  log();
307
307
  app.events.on(INTERNAL_RUN_COMPLETE, onRunComplete);
308
308
  } else {
309
- logger2.debug("No active rns detected");
309
+ logger2.debug("No active runs detected, closing immediately");
310
310
  resolve5();
311
311
  }
312
312
  });
@@ -381,7 +381,10 @@ var claim = (app, logger2 = mockLogger, options = {}) => {
381
381
  }
382
382
  logger2.debug("requesting run...");
383
383
  app.queueChannel.push(CLAIM, { demand: 1 }).receive("ok", ({ runs }) => {
384
- logger2.debug(`pulled ${runs.length} runs`);
384
+ logger2.debug(
385
+ `claimed ${runs.length} runs: `,
386
+ runs.map((r) => r.id).join(",")
387
+ );
385
388
  if (!runs?.length) {
386
389
  return reject(new Error("No runs returned"));
387
390
  }
@@ -404,10 +407,10 @@ var claim = (app, logger2 = mockLogger, options = {}) => {
404
407
  app.execute(run2);
405
408
  resolve5();
406
409
  });
407
- }).receive("error", () => {
408
- logger2.debug("pull err");
410
+ }).receive("error", (e) => {
411
+ logger2.error("Error on claim", e);
409
412
  }).receive("timeout", () => {
410
- logger2.debug("pull timeout");
413
+ logger2.error("TIMEOUT on claim. Runs may be lost.");
411
414
  reject(new Error("timeout"));
412
415
  });
413
416
  });
@@ -471,13 +474,19 @@ var convert_lightning_plan_default = (run2) => {
471
474
  const runtimeOpts = {};
472
475
  const engineOpts = {};
473
476
  if (run2.options) {
474
- if (run2.options.run_timeout_ms) {
477
+ if ("run_timeout_ms" in run2.options) {
475
478
  engineOpts.runTimeoutMs = run2.options.run_timeout_ms;
476
479
  }
477
- if (run2.options.sanitize) {
480
+ if ("payload_limit_mb" in run2.options) {
481
+ engineOpts.payloadLimitMb = run2.options.payload_limit_mb;
482
+ }
483
+ if ("run_memory_limit_mb" in run2.options) {
484
+ engineOpts.memoryLimitMb = run2.options.run_memory_limit_mb;
485
+ }
486
+ if ("sanitize" in run2.options) {
478
487
  engineOpts.sanitize = run2.options.sanitize;
479
488
  }
480
- if (run2.options.hasOwnProperty("output_dataclips")) {
489
+ if ("output_dataclips" in run2.options) {
481
490
  engineOpts.outputDataclips = run2.options.output_dataclips;
482
491
  }
483
492
  }
@@ -666,7 +675,7 @@ ${prefix("worker")}${versions.worker || "unknown"}`;
666
675
  // src/events/run-start.ts
667
676
  init_package();
668
677
  async function onRunStart(context, event) {
669
- const { channel, state } = context;
678
+ const { channel, state, options = {} } = context;
670
679
  const time = (timestamp() - BigInt(1e7)).toString();
671
680
  const versionLogContext = {
672
681
  ...context,
@@ -680,6 +689,14 @@ async function onRunStart(context, event) {
680
689
  ...event.versions
681
690
  };
682
691
  await sendEvent(channel, RUN_START, { versions });
692
+ if ("payloadLimitMb" in options) {
693
+ await onJobLog(versionLogContext, {
694
+ time,
695
+ message: [`Payload limit: ${options.payloadLimitMb}mb`],
696
+ level: "info",
697
+ name: "RTE"
698
+ });
699
+ }
683
700
  const versionMessage = versions_default(versions);
684
701
  await onJobLog(versionLogContext, {
685
702
  time,
@@ -691,6 +708,7 @@ async function onRunStart(context, event) {
691
708
 
692
709
  // src/events/step-complete.ts
693
710
  import crypto4 from "node:crypto";
711
+ import { timestamp as timestamp2 } from "@openfn/logger";
694
712
 
695
713
  // src/api/reasons.ts
696
714
  var calculateJobExitReason = (jobId, state = { data: {} }, error) => {
@@ -725,8 +743,25 @@ var calculateRunExitReason = (state) => {
725
743
  return { reason: "success", error_type: null, error_message: null };
726
744
  };
727
745
 
746
+ // src/util/ensure-payload-size.ts
747
+ var ensure_payload_size_default = (payload, limit_mb) => {
748
+ if (!isNaN(limit_mb)) {
749
+ const limit = limit_mb;
750
+ const size_bytes = Buffer.byteLength(payload, "utf8");
751
+ const size_mb = size_bytes / 1024 / 1024;
752
+ if (size_mb > limit) {
753
+ const e = new Error();
754
+ e.severity = "kill";
755
+ e.name = "PAYLOAD_TOO_LARGE";
756
+ e.message = `The payload exceeded the size limit of ${limit}mb`;
757
+ throw e;
758
+ }
759
+ }
760
+ };
761
+
728
762
  // src/events/step-complete.ts
729
- function onStepComplete({ channel, state, options }, event, error) {
763
+ async function onStepComplete(context, event, error) {
764
+ const { channel, state, options } = context;
730
765
  const dataclipId = crypto4.randomUUID();
731
766
  const step_id = state.activeStep;
732
767
  const job_id = state.activeJob;
@@ -741,26 +776,35 @@ function onStepComplete({ channel, state, options }, event, error) {
741
776
  event.next?.forEach((nextJobId) => {
742
777
  state.inputDataclips[nextJobId] = dataclipId;
743
778
  });
744
- const { reason, error_message, error_type } = calculateJobExitReason(
745
- job_id,
746
- event.state,
747
- error
748
- );
749
- state.reasons[job_id] = { reason, error_message, error_type };
750
779
  const evt = {
751
780
  step_id,
752
781
  job_id,
753
- output_dataclip_id: dataclipId,
754
- reason,
755
- error_message,
756
- error_type,
757
782
  mem: event.mem,
758
783
  duration: event.duration,
759
784
  thread_id: event.threadId
760
785
  };
761
- if (!options || options.outputDataclips !== false) {
762
- evt.output_dataclip = stringify_default(outputState);
786
+ try {
787
+ if (!options || options.outputDataclips !== false) {
788
+ const payload = stringify_default(outputState);
789
+ ensure_payload_size_default(payload, options?.payloadLimitMb);
790
+ evt.output_dataclip = payload;
791
+ }
792
+ evt.output_dataclip_id = dataclipId;
793
+ } catch (e) {
794
+ evt.output_dataclip_error = "DATACLIP_TOO_LARGE";
795
+ const time = (timestamp2() - BigInt(1e7)).toString();
796
+ await onJobLog(context, {
797
+ time,
798
+ message: [
799
+ "Dataclip too large. This dataclip will not be sent back to lighting."
800
+ ],
801
+ level: "info",
802
+ name: "R/T"
803
+ });
763
804
  }
805
+ const reason = calculateJobExitReason(job_id, event.state, error);
806
+ state.reasons[job_id] = reason;
807
+ Object.assign(evt, reason);
764
808
  return sendEvent(channel, STEP_COMPLETE, evt);
765
809
  }
766
810
 
@@ -779,9 +823,9 @@ async function onStepStart(context, event) {
779
823
  }
780
824
 
781
825
  // src/util/log-final-reason.ts
782
- import { timestamp as timestamp2 } from "@openfn/logger";
826
+ import { timestamp as timestamp3 } from "@openfn/logger";
783
827
  var log_final_reason_default = async (context, reason) => {
784
- const time = (timestamp2() - BigInt(1e7)).toString();
828
+ const time = (timestamp3() - BigInt(1e7)).toString();
785
829
  let message = `Run complete with status: ${reason.reason}`;
786
830
  if (reason.reason !== "success") {
787
831
  message += `
@@ -931,11 +975,25 @@ function onJobError(context, event) {
931
975
  return onStepComplete(context, event, event.error);
932
976
  }
933
977
  }
934
- function onJobLog({ channel, state }, event) {
978
+ function onJobLog({ channel, state, options }, event) {
935
979
  const timeInMicroseconds = BigInt(event.time) / BigInt(1e3);
980
+ let message = event.message;
981
+ try {
982
+ if (typeof event.message === "string") {
983
+ ensure_payload_size_default(event.message, options?.payloadLimitMb);
984
+ message = JSON.parse(message);
985
+ } else if (event.message) {
986
+ const payload = stringify_default(event.message);
987
+ ensure_payload_size_default(payload, options?.payloadLimitMb);
988
+ }
989
+ } catch (e) {
990
+ message = [
991
+ `(Log message redacted: exceeds ${options.payloadLimitMb}mb memory limit)`
992
+ ];
993
+ }
936
994
  const log = {
937
995
  run_id: state.plan.id,
938
- message: typeof event.message === "string" ? JSON.parse(event.message) : event.message,
996
+ message,
939
997
  source: event.name,
940
998
  level: event.level,
941
999
  timestamp: timeInMicroseconds.toString()
@@ -1026,7 +1084,7 @@ var generateWorkerToken = async (secret, workerId, logger2) => {
1026
1084
  var worker_token_default = generateWorkerToken;
1027
1085
 
1028
1086
  // src/channels/worker-queue.ts
1029
- var connectToWorkerQueue = (endpoint, serverId, secret, logger2, SocketConstructor = PhxSocket) => {
1087
+ var connectToWorkerQueue = (endpoint, serverId, secret, timeout = 10, logger2, SocketConstructor = PhxSocket) => {
1030
1088
  const events = new EventEmitter2();
1031
1089
  worker_token_default(secret, serverId, logger2).then(async (token) => {
1032
1090
  const pkg = await Promise.resolve().then(() => (init_package(), package_exports));
@@ -1037,7 +1095,8 @@ var connectToWorkerQueue = (endpoint, serverId, secret, logger2, SocketConstruct
1037
1095
  };
1038
1096
  const socket = new SocketConstructor(endpoint, {
1039
1097
  params,
1040
- transport: WebSocket
1098
+ transport: WebSocket,
1099
+ timeout: timeout * 1e3
1041
1100
  });
1042
1101
  let didOpen = false;
1043
1102
  socket.onOpen(() => {
@@ -1069,7 +1128,7 @@ var connectToWorkerQueue = (endpoint, serverId, secret, logger2, SocketConstruct
1069
1128
  var worker_queue_default = connectToWorkerQueue;
1070
1129
 
1071
1130
  // src/server.ts
1072
- var DEFAULT_PORT = 1234;
1131
+ var DEFAULT_PORT = 2222;
1073
1132
  var MIN_BACKOFF = 1e3;
1074
1133
  var MAX_BACKOFF = 1e3 * 30;
1075
1134
  function connect(app, logger2, options = {}) {
@@ -1091,13 +1150,12 @@ function connect(app, logger2, options = {}) {
1091
1150
  options.maxWorkflows
1092
1151
  );
1093
1152
  } else {
1153
+ const port = app.server?.address().port;
1094
1154
  logger2.break();
1095
- logger2.warn("Workloop not starting");
1155
+ logger2.warn("Noloop active: workloop has not started");
1096
1156
  logger2.info("This server will not auto-pull work from lightning.");
1097
1157
  logger2.info("You can manually claim by posting to /claim, eg:");
1098
- logger2.info(
1099
- ` curl -X POST http://locahost:${options.port || DEFAULT_PORT}/claim`
1100
- );
1158
+ logger2.info(` curl -X POST http://localhost:${port}/claim`);
1101
1159
  logger2.break();
1102
1160
  }
1103
1161
  };
@@ -1121,7 +1179,13 @@ function connect(app, logger2, options = {}) {
1121
1179
  );
1122
1180
  logger2.debug(e);
1123
1181
  };
1124
- worker_queue_default(options.lightning, app.id, options.secret, logger2).on("connect", onConnect).on("disconnect", onDisconnect).on("error", onError);
1182
+ worker_queue_default(
1183
+ options.lightning,
1184
+ app.id,
1185
+ options.secret,
1186
+ options.socketTimeoutSeconds,
1187
+ logger2
1188
+ ).on("connect", onConnect).on("disconnect", onDisconnect).on("error", onError);
1125
1189
  }
1126
1190
  function createServer(engine, options = {}) {
1127
1191
  const logger2 = options.logger || createMockLogger2();
@@ -1144,16 +1208,19 @@ function createServer(engine, options = {}) {
1144
1208
  process.send?.("READY");
1145
1209
  router.get("/livez", healthcheck_default);
1146
1210
  router.get("/", healthcheck_default);
1147
- app.options = options || {};
1211
+ app.options = options;
1148
1212
  app.execute = async ({ id, token }) => {
1149
1213
  if (app.socket) {
1150
1214
  app.workflows[id] = true;
1151
1215
  const {
1152
1216
  channel: runChannel,
1153
1217
  plan,
1154
- options: options2,
1218
+ options: options2 = {},
1155
1219
  input
1156
1220
  } = await run_default(app.socket, token, id, logger2);
1221
+ if (!("payloadLimitMb" in options2)) {
1222
+ options2.payloadLimitMb = app.options.payloadLimitMb;
1223
+ }
1157
1224
  const onFinish = () => {
1158
1225
  logger2.debug(`workflow ${id} complete: releasing worker`);
1159
1226
  delete app.workflows[id];
@@ -6066,6 +6133,9 @@ var Yargs = YargsFactory(esm_default);
6066
6133
  var yargs_default = Yargs;
6067
6134
 
6068
6135
  // src/util/cli.ts
6136
+ var DEFAULT_PORT2 = 2222;
6137
+ var DEFAULT_WORKER_CAPACITY = 5;
6138
+ var DEFAULT_SOCKET_TIMEOUT_SECONDS = 10;
6069
6139
  function setArg(argValue, envValue, defaultValue) {
6070
6140
  if (Array.isArray(defaultValue) && !argValue && typeof envValue === "string") {
6071
6141
  return envValue.split(",");
@@ -6082,16 +6152,18 @@ function parseArgs(argv) {
6082
6152
  WORKER_LIGHTNING_PUBLIC_KEY,
6083
6153
  WORKER_LIGHTNING_SERVICE_URL,
6084
6154
  WORKER_LOG_LEVEL,
6155
+ WORKER_MAX_PAYLOAD_MB,
6085
6156
  WORKER_MAX_RUN_DURATION_SECONDS,
6086
6157
  WORKER_MAX_RUN_MEMORY_MB,
6087
6158
  WORKER_PORT,
6088
6159
  WORKER_REPO_DIR,
6089
6160
  WORKER_SECRET,
6090
- WORKER_STATE_PROPS_TO_REMOVE
6161
+ WORKER_STATE_PROPS_TO_REMOVE,
6162
+ WORKER_SOCKET_TIMEOUT_SECONDS
6091
6163
  } = process.env;
6092
6164
  const parser2 = yargs_default(hideBin(argv)).command("server", "Start a ws-worker server").option("port", {
6093
6165
  alias: "p",
6094
- description: "Port to run the server on. Env: WORKER_PORT",
6166
+ description: `Port to run the server on. Default ${DEFAULT_PORT2}. Env: WORKER_PORT`,
6095
6167
  type: "number"
6096
6168
  }).option("lightning", {
6097
6169
  alias: ["l", "lightning-service-url"],
@@ -6102,6 +6174,8 @@ function parseArgs(argv) {
6102
6174
  }).option("secret", {
6103
6175
  alias: "s",
6104
6176
  description: "Worker secret. (comes from WORKER_SECRET by default). Env: WORKER_SECRET"
6177
+ }).option("socket-timeout", {
6178
+ description: `Timeout for websockets to Lighting, in seconds. Defaults to 10.`
6105
6179
  }).option("lightning-public-key", {
6106
6180
  description: "Base64-encoded public key. Used to verify run tokens. Env: WORKER_LIGHTNING_PUBLIC_KEY"
6107
6181
  }).option("log", {
@@ -6117,7 +6191,7 @@ function parseArgs(argv) {
6117
6191
  }).option("backoff", {
6118
6192
  description: "Claim backoff rules: min/max (in seconds). Env: WORKER_BACKOFF"
6119
6193
  }).option("capacity", {
6120
- description: "max concurrent workers. Env: WORKER_CAPACITY",
6194
+ description: `max concurrent workers. Default ${DEFAULT_WORKER_CAPACITY}. Env: WORKER_CAPACITY`,
6121
6195
  type: "number"
6122
6196
  }).option("state-props-to-remove", {
6123
6197
  description: "A list of properties to remove from the final state returned by a job. Env: WORKER_STATE_PROPS_TO_REMOVE",
@@ -6125,6 +6199,9 @@ function parseArgs(argv) {
6125
6199
  }).option("run-memory", {
6126
6200
  description: "Maximum memory allocated to a single run, in mb. Env: WORKER_MAX_RUN_MEMORY_MB",
6127
6201
  type: "number"
6202
+ }).option("payload-memory", {
6203
+ description: "Maximum memory allocated to a single run, in mb. Env: WORKER_MAX_PAYLOAD_MB",
6204
+ type: "number"
6128
6205
  }).option("max-run-duration-seconds", {
6129
6206
  alias: "t",
6130
6207
  description: "Default run timeout for the server, in seconds. Env: WORKER_MAX_RUN_DURATION_SECONDS",
@@ -6133,7 +6210,7 @@ function parseArgs(argv) {
6133
6210
  const args2 = parser2.parse();
6134
6211
  return {
6135
6212
  ...args2,
6136
- port: setArg(args2.port, WORKER_PORT, 2222),
6213
+ port: setArg(args2.port, WORKER_PORT, DEFAULT_PORT2),
6137
6214
  lightning: setArg(
6138
6215
  args2.lightning,
6139
6216
  WORKER_LIGHTNING_SERVICE_URL,
@@ -6147,17 +6224,23 @@ function parseArgs(argv) {
6147
6224
  ),
6148
6225
  log: setArg(args2.log, WORKER_LOG_LEVEL, "debug"),
6149
6226
  backoff: setArg(args2.backoff, WORKER_BACKOFF, "1/10"),
6150
- capacity: setArg(args2.capacity, WORKER_CAPACITY, 5),
6227
+ capacity: setArg(args2.capacity, WORKER_CAPACITY, DEFAULT_WORKER_CAPACITY),
6151
6228
  statePropsToRemove: setArg(
6152
6229
  args2.statePropsToRemove,
6153
6230
  WORKER_STATE_PROPS_TO_REMOVE,
6154
6231
  ["configuration", "response"]
6155
6232
  ),
6156
6233
  runMemory: setArg(args2.runMemory, WORKER_MAX_RUN_MEMORY_MB, 500),
6234
+ payloadMemory: setArg(args2.payloadMemory, WORKER_MAX_PAYLOAD_MB, 10),
6157
6235
  maxRunDurationSeconds: setArg(
6158
6236
  args2.maxRunDurationSeconds,
6159
6237
  WORKER_MAX_RUN_DURATION_SECONDS,
6160
6238
  300
6239
+ ),
6240
+ socketTimeoutSeconds: setArg(
6241
+ args2.socketTimeoutSeconds,
6242
+ WORKER_SOCKET_TIMEOUT_SECONDS,
6243
+ DEFAULT_SOCKET_TIMEOUT_SECONDS
6161
6244
  )
6162
6245
  };
6163
6246
  }
@@ -6187,7 +6270,8 @@ function engineReady(engine) {
6187
6270
  min: minBackoff,
6188
6271
  max: maxBackoff
6189
6272
  },
6190
- maxWorkflows: args.capacity
6273
+ maxWorkflows: args.capacity,
6274
+ payloadLimitMb: args.payloadMemory
6191
6275
  };
6192
6276
  if (args.lightningPublicKey) {
6193
6277
  logger.info(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfn/ws-worker",
3
- "version": "1.4.1",
3
+ "version": "1.5.1",
4
4
  "description": "A Websocket Worker to connect Lightning to a Runtime Engine",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -24,8 +24,8 @@
24
24
  "ws": "^8.14.1",
25
25
  "@openfn/engine-multi": "1.2.1",
26
26
  "@openfn/lexicon": "^1.0.2",
27
- "@openfn/runtime": "1.4.1",
28
- "@openfn/logger": "1.0.1"
27
+ "@openfn/logger": "1.0.1",
28
+ "@openfn/runtime": "1.4.1"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/koa": "^2.13.5",