@openfn/ws-worker 1.5.0 → 1.6.0

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,26 @@
1
1
  # ws-worker
2
2
 
3
+ ## 1.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - eaa3859: Include timestamps in key events
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [870a836]
12
+ - Updated dependencies [44f7f57]
13
+ - @openfn/engine-multi@1.2.2
14
+ - @openfn/lexicon@1.1.0
15
+ - @openfn/runtime@1.4.1
16
+
17
+ ## 1.5.1
18
+
19
+ ### Patch Changes
20
+
21
+ - a08fb47: Update CLI docs
22
+ Add WORKER_MAX_SOCKET_TIMEOUT_SECONDS
23
+
3
24
  ## 1.5.0
4
25
 
5
26
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -65,6 +65,7 @@ declare type ServerOptions = {
65
65
  min?: number;
66
66
  max?: number;
67
67
  };
68
+ socketTimeoutSeconds?: number;
68
69
  payloadLimitMb?: number;
69
70
  };
70
71
  interface ServerApp extends Koa {
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.5.0";
32
+ version = "1.6.0";
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
  });
@@ -505,6 +508,9 @@ var createThrottler = () => {
505
508
  };
506
509
  var throttle_default = createThrottler;
507
510
 
511
+ // src/util/timestamp.ts
512
+ var timeInMicroseconds = (time) => time && (BigInt(time) / BigInt(1e3)).toString();
513
+
508
514
  // src/events/run-start.ts
509
515
  import { timestamp } from "@openfn/logger";
510
516
 
@@ -546,7 +552,10 @@ async function onRunStart(context, event) {
546
552
  worker: package_default.version,
547
553
  ...event.versions
548
554
  };
549
- await sendEvent(channel, RUN_START, { versions });
555
+ await sendEvent(channel, RUN_START, {
556
+ versions,
557
+ timestamp: timeInMicroseconds(event.time)
558
+ });
550
559
  if ("payloadLimitMb" in options) {
551
560
  await onJobLog(versionLogContext, {
552
561
  time,
@@ -639,7 +648,8 @@ async function onStepComplete(context, event, error) {
639
648
  job_id,
640
649
  mem: event.mem,
641
650
  duration: event.duration,
642
- thread_id: event.threadId
651
+ thread_id: event.threadId,
652
+ timestamp: timeInMicroseconds(event.time)
643
653
  };
644
654
  try {
645
655
  if (!options || options.outputDataclips !== false) {
@@ -676,7 +686,8 @@ async function onStepStart(context, event) {
676
686
  await sendEvent(channel, STEP_START, {
677
687
  step_id: state.activeStep,
678
688
  job_id: state.activeJob,
679
- input_dataclip_id
689
+ input_dataclip_id,
690
+ timestamp: timeInMicroseconds(event.time)
680
691
  });
681
692
  }
682
693
 
@@ -698,7 +709,7 @@ ${reason.error_type}: ${reason.error_message || "unknown"}`;
698
709
  };
699
710
 
700
711
  // src/events/run-complete.ts
701
- async function onWorkflowComplete(context, _event) {
712
+ async function onWorkflowComplete(context, event) {
702
713
  const { state, channel, onFinish, logger } = context;
703
714
  const result = state.dataclips[state.lastDataclipId];
704
715
  const reason = calculateRunExitReason(state);
@@ -706,6 +717,7 @@ async function onWorkflowComplete(context, _event) {
706
717
  try {
707
718
  await sendEvent(channel, RUN_COMPLETE, {
708
719
  final_dataclip_id: state.lastDataclipId,
720
+ timestamp: timeInMicroseconds(event.time),
709
721
  ...reason
710
722
  });
711
723
  } catch (e) {
@@ -834,7 +846,6 @@ function onJobError(context, event) {
834
846
  }
835
847
  }
836
848
  function onJobLog({ channel, state, options }, event) {
837
- const timeInMicroseconds = BigInt(event.time) / BigInt(1e3);
838
849
  let message = event.message;
839
850
  try {
840
851
  if (typeof event.message === "string") {
@@ -854,7 +865,7 @@ function onJobLog({ channel, state, options }, event) {
854
865
  message,
855
866
  source: event.name,
856
867
  level: event.level,
857
- timestamp: timeInMicroseconds.toString()
868
+ timestamp: timeInMicroseconds(event.time)
858
869
  };
859
870
  if (state.activeStep) {
860
871
  log.step_id = state.activeStep;
@@ -942,7 +953,7 @@ var generateWorkerToken = async (secret, workerId, logger) => {
942
953
  var worker_token_default = generateWorkerToken;
943
954
 
944
955
  // src/channels/worker-queue.ts
945
- var connectToWorkerQueue = (endpoint, serverId, secret, logger, SocketConstructor = PhxSocket) => {
956
+ var connectToWorkerQueue = (endpoint, serverId, secret, timeout = 10, logger, SocketConstructor = PhxSocket) => {
946
957
  const events = new EventEmitter();
947
958
  worker_token_default(secret, serverId, logger).then(async (token) => {
948
959
  const pkg = await Promise.resolve().then(() => (init_package(), package_exports));
@@ -953,7 +964,8 @@ var connectToWorkerQueue = (endpoint, serverId, secret, logger, SocketConstructo
953
964
  };
954
965
  const socket = new SocketConstructor(endpoint, {
955
966
  params,
956
- transport: WebSocket
967
+ transport: WebSocket,
968
+ timeout: timeout * 1e3
957
969
  });
958
970
  let didOpen = false;
959
971
  socket.onOpen(() => {
@@ -985,7 +997,7 @@ var connectToWorkerQueue = (endpoint, serverId, secret, logger, SocketConstructo
985
997
  var worker_queue_default = connectToWorkerQueue;
986
998
 
987
999
  // src/server.ts
988
- var DEFAULT_PORT = 1234;
1000
+ var DEFAULT_PORT = 2222;
989
1001
  var MIN_BACKOFF = 1e3;
990
1002
  var MAX_BACKOFF = 1e3 * 30;
991
1003
  function connect(app, logger, options = {}) {
@@ -1007,13 +1019,12 @@ function connect(app, logger, options = {}) {
1007
1019
  options.maxWorkflows
1008
1020
  );
1009
1021
  } else {
1022
+ const port = app.server?.address().port;
1010
1023
  logger.break();
1011
- logger.warn("Workloop not starting");
1024
+ logger.warn("Noloop active: workloop has not started");
1012
1025
  logger.info("This server will not auto-pull work from lightning.");
1013
1026
  logger.info("You can manually claim by posting to /claim, eg:");
1014
- logger.info(
1015
- ` curl -X POST http://locahost:${options.port || DEFAULT_PORT}/claim`
1016
- );
1027
+ logger.info(` curl -X POST http://localhost:${port}/claim`);
1017
1028
  logger.break();
1018
1029
  }
1019
1030
  };
@@ -1037,7 +1048,13 @@ function connect(app, logger, options = {}) {
1037
1048
  );
1038
1049
  logger.debug(e);
1039
1050
  };
1040
- worker_queue_default(options.lightning, app.id, options.secret, logger).on("connect", onConnect).on("disconnect", onDisconnect).on("error", onError);
1051
+ worker_queue_default(
1052
+ options.lightning,
1053
+ app.id,
1054
+ options.secret,
1055
+ options.socketTimeoutSeconds,
1056
+ logger
1057
+ ).on("connect", onConnect).on("disconnect", onDisconnect).on("error", onError);
1041
1058
  }
1042
1059
  function createServer(engine, options = {}) {
1043
1060
  const logger = options.logger || createMockLogger2();
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.5.0";
40
+ version = "1.6.0";
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
  });
@@ -644,6 +647,9 @@ var createThrottler = () => {
644
647
  };
645
648
  var throttle_default = createThrottler;
646
649
 
650
+ // src/util/timestamp.ts
651
+ var timeInMicroseconds = (time) => time && (BigInt(time) / BigInt(1e3)).toString();
652
+
647
653
  // src/events/run-start.ts
648
654
  import { timestamp } from "@openfn/logger";
649
655
 
@@ -685,7 +691,10 @@ async function onRunStart(context, event) {
685
691
  worker: package_default.version,
686
692
  ...event.versions
687
693
  };
688
- await sendEvent(channel, RUN_START, { versions });
694
+ await sendEvent(channel, RUN_START, {
695
+ versions,
696
+ timestamp: timeInMicroseconds(event.time)
697
+ });
689
698
  if ("payloadLimitMb" in options) {
690
699
  await onJobLog(versionLogContext, {
691
700
  time,
@@ -778,7 +787,8 @@ async function onStepComplete(context, event, error) {
778
787
  job_id,
779
788
  mem: event.mem,
780
789
  duration: event.duration,
781
- thread_id: event.threadId
790
+ thread_id: event.threadId,
791
+ timestamp: timeInMicroseconds(event.time)
782
792
  };
783
793
  try {
784
794
  if (!options || options.outputDataclips !== false) {
@@ -815,7 +825,8 @@ async function onStepStart(context, event) {
815
825
  await sendEvent(channel, STEP_START, {
816
826
  step_id: state.activeStep,
817
827
  job_id: state.activeJob,
818
- input_dataclip_id
828
+ input_dataclip_id,
829
+ timestamp: timeInMicroseconds(event.time)
819
830
  });
820
831
  }
821
832
 
@@ -837,7 +848,7 @@ ${reason.error_type}: ${reason.error_message || "unknown"}`;
837
848
  };
838
849
 
839
850
  // src/events/run-complete.ts
840
- async function onWorkflowComplete(context, _event) {
851
+ async function onWorkflowComplete(context, event) {
841
852
  const { state, channel, onFinish, logger: logger2 } = context;
842
853
  const result = state.dataclips[state.lastDataclipId];
843
854
  const reason = calculateRunExitReason(state);
@@ -845,6 +856,7 @@ async function onWorkflowComplete(context, _event) {
845
856
  try {
846
857
  await sendEvent(channel, RUN_COMPLETE, {
847
858
  final_dataclip_id: state.lastDataclipId,
859
+ timestamp: timeInMicroseconds(event.time),
848
860
  ...reason
849
861
  });
850
862
  } catch (e) {
@@ -973,7 +985,6 @@ function onJobError(context, event) {
973
985
  }
974
986
  }
975
987
  function onJobLog({ channel, state, options }, event) {
976
- const timeInMicroseconds = BigInt(event.time) / BigInt(1e3);
977
988
  let message = event.message;
978
989
  try {
979
990
  if (typeof event.message === "string") {
@@ -993,7 +1004,7 @@ function onJobLog({ channel, state, options }, event) {
993
1004
  message,
994
1005
  source: event.name,
995
1006
  level: event.level,
996
- timestamp: timeInMicroseconds.toString()
1007
+ timestamp: timeInMicroseconds(event.time)
997
1008
  };
998
1009
  if (state.activeStep) {
999
1010
  log.step_id = state.activeStep;
@@ -1081,7 +1092,7 @@ var generateWorkerToken = async (secret, workerId, logger2) => {
1081
1092
  var worker_token_default = generateWorkerToken;
1082
1093
 
1083
1094
  // src/channels/worker-queue.ts
1084
- var connectToWorkerQueue = (endpoint, serverId, secret, logger2, SocketConstructor = PhxSocket) => {
1095
+ var connectToWorkerQueue = (endpoint, serverId, secret, timeout = 10, logger2, SocketConstructor = PhxSocket) => {
1085
1096
  const events = new EventEmitter2();
1086
1097
  worker_token_default(secret, serverId, logger2).then(async (token) => {
1087
1098
  const pkg = await Promise.resolve().then(() => (init_package(), package_exports));
@@ -1092,7 +1103,8 @@ var connectToWorkerQueue = (endpoint, serverId, secret, logger2, SocketConstruct
1092
1103
  };
1093
1104
  const socket = new SocketConstructor(endpoint, {
1094
1105
  params,
1095
- transport: WebSocket
1106
+ transport: WebSocket,
1107
+ timeout: timeout * 1e3
1096
1108
  });
1097
1109
  let didOpen = false;
1098
1110
  socket.onOpen(() => {
@@ -1124,7 +1136,7 @@ var connectToWorkerQueue = (endpoint, serverId, secret, logger2, SocketConstruct
1124
1136
  var worker_queue_default = connectToWorkerQueue;
1125
1137
 
1126
1138
  // src/server.ts
1127
- var DEFAULT_PORT = 1234;
1139
+ var DEFAULT_PORT = 2222;
1128
1140
  var MIN_BACKOFF = 1e3;
1129
1141
  var MAX_BACKOFF = 1e3 * 30;
1130
1142
  function connect(app, logger2, options = {}) {
@@ -1146,13 +1158,12 @@ function connect(app, logger2, options = {}) {
1146
1158
  options.maxWorkflows
1147
1159
  );
1148
1160
  } else {
1161
+ const port = app.server?.address().port;
1149
1162
  logger2.break();
1150
- logger2.warn("Workloop not starting");
1163
+ logger2.warn("Noloop active: workloop has not started");
1151
1164
  logger2.info("This server will not auto-pull work from lightning.");
1152
1165
  logger2.info("You can manually claim by posting to /claim, eg:");
1153
- logger2.info(
1154
- ` curl -X POST http://locahost:${options.port || DEFAULT_PORT}/claim`
1155
- );
1166
+ logger2.info(` curl -X POST http://localhost:${port}/claim`);
1156
1167
  logger2.break();
1157
1168
  }
1158
1169
  };
@@ -1176,7 +1187,13 @@ function connect(app, logger2, options = {}) {
1176
1187
  );
1177
1188
  logger2.debug(e);
1178
1189
  };
1179
- worker_queue_default(options.lightning, app.id, options.secret, logger2).on("connect", onConnect).on("disconnect", onDisconnect).on("error", onError);
1190
+ worker_queue_default(
1191
+ options.lightning,
1192
+ app.id,
1193
+ options.secret,
1194
+ options.socketTimeoutSeconds,
1195
+ logger2
1196
+ ).on("connect", onConnect).on("disconnect", onDisconnect).on("error", onError);
1180
1197
  }
1181
1198
  function createServer(engine, options = {}) {
1182
1199
  const logger2 = options.logger || createMockLogger2();
@@ -6124,6 +6141,9 @@ var Yargs = YargsFactory(esm_default);
6124
6141
  var yargs_default = Yargs;
6125
6142
 
6126
6143
  // src/util/cli.ts
6144
+ var DEFAULT_PORT2 = 2222;
6145
+ var DEFAULT_WORKER_CAPACITY = 5;
6146
+ var DEFAULT_SOCKET_TIMEOUT_SECONDS = 10;
6127
6147
  function setArg(argValue, envValue, defaultValue) {
6128
6148
  if (Array.isArray(defaultValue) && !argValue && typeof envValue === "string") {
6129
6149
  return envValue.split(",");
@@ -6146,11 +6166,12 @@ function parseArgs(argv) {
6146
6166
  WORKER_PORT,
6147
6167
  WORKER_REPO_DIR,
6148
6168
  WORKER_SECRET,
6149
- WORKER_STATE_PROPS_TO_REMOVE
6169
+ WORKER_STATE_PROPS_TO_REMOVE,
6170
+ WORKER_SOCKET_TIMEOUT_SECONDS
6150
6171
  } = process.env;
6151
6172
  const parser2 = yargs_default(hideBin(argv)).command("server", "Start a ws-worker server").option("port", {
6152
6173
  alias: "p",
6153
- description: "Port to run the server on. Env: WORKER_PORT",
6174
+ description: `Port to run the server on. Default ${DEFAULT_PORT2}. Env: WORKER_PORT`,
6154
6175
  type: "number"
6155
6176
  }).option("lightning", {
6156
6177
  alias: ["l", "lightning-service-url"],
@@ -6161,6 +6182,8 @@ function parseArgs(argv) {
6161
6182
  }).option("secret", {
6162
6183
  alias: "s",
6163
6184
  description: "Worker secret. (comes from WORKER_SECRET by default). Env: WORKER_SECRET"
6185
+ }).option("socket-timeout", {
6186
+ description: `Timeout for websockets to Lighting, in seconds. Defaults to 10.`
6164
6187
  }).option("lightning-public-key", {
6165
6188
  description: "Base64-encoded public key. Used to verify run tokens. Env: WORKER_LIGHTNING_PUBLIC_KEY"
6166
6189
  }).option("log", {
@@ -6176,7 +6199,7 @@ function parseArgs(argv) {
6176
6199
  }).option("backoff", {
6177
6200
  description: "Claim backoff rules: min/max (in seconds). Env: WORKER_BACKOFF"
6178
6201
  }).option("capacity", {
6179
- description: "max concurrent workers. Env: WORKER_CAPACITY",
6202
+ description: `max concurrent workers. Default ${DEFAULT_WORKER_CAPACITY}. Env: WORKER_CAPACITY`,
6180
6203
  type: "number"
6181
6204
  }).option("state-props-to-remove", {
6182
6205
  description: "A list of properties to remove from the final state returned by a job. Env: WORKER_STATE_PROPS_TO_REMOVE",
@@ -6195,7 +6218,7 @@ function parseArgs(argv) {
6195
6218
  const args2 = parser2.parse();
6196
6219
  return {
6197
6220
  ...args2,
6198
- port: setArg(args2.port, WORKER_PORT, 2222),
6221
+ port: setArg(args2.port, WORKER_PORT, DEFAULT_PORT2),
6199
6222
  lightning: setArg(
6200
6223
  args2.lightning,
6201
6224
  WORKER_LIGHTNING_SERVICE_URL,
@@ -6209,7 +6232,7 @@ function parseArgs(argv) {
6209
6232
  ),
6210
6233
  log: setArg(args2.log, WORKER_LOG_LEVEL, "debug"),
6211
6234
  backoff: setArg(args2.backoff, WORKER_BACKOFF, "1/10"),
6212
- capacity: setArg(args2.capacity, WORKER_CAPACITY, 5),
6235
+ capacity: setArg(args2.capacity, WORKER_CAPACITY, DEFAULT_WORKER_CAPACITY),
6213
6236
  statePropsToRemove: setArg(
6214
6237
  args2.statePropsToRemove,
6215
6238
  WORKER_STATE_PROPS_TO_REMOVE,
@@ -6221,6 +6244,11 @@ function parseArgs(argv) {
6221
6244
  args2.maxRunDurationSeconds,
6222
6245
  WORKER_MAX_RUN_DURATION_SECONDS,
6223
6246
  300
6247
+ ),
6248
+ socketTimeoutSeconds: setArg(
6249
+ args2.socketTimeoutSeconds,
6250
+ WORKER_SOCKET_TIMEOUT_SECONDS,
6251
+ DEFAULT_SOCKET_TIMEOUT_SECONDS
6224
6252
  )
6225
6253
  };
6226
6254
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfn/ws-worker",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "A Websocket Worker to connect Lightning to a Runtime Engine",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -22,10 +22,10 @@
22
22
  "koa-logger": "^3.2.1",
23
23
  "phoenix": "1.7.10",
24
24
  "ws": "^8.14.1",
25
- "@openfn/engine-multi": "1.2.1",
26
- "@openfn/logger": "1.0.1",
27
- "@openfn/lexicon": "^1.0.2",
28
- "@openfn/runtime": "1.4.1"
25
+ "@openfn/engine-multi": "1.2.2",
26
+ "@openfn/lexicon": "^1.1.0",
27
+ "@openfn/runtime": "1.4.1",
28
+ "@openfn/logger": "1.0.1"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/koa": "^2.13.5",
@@ -42,7 +42,7 @@
42
42
  "tsup": "^6.2.3",
43
43
  "typescript": "^4.6.4",
44
44
  "yargs": "^17.6.2",
45
- "@openfn/lightning-mock": "2.0.15"
45
+ "@openfn/lightning-mock": "2.0.16"
46
46
  },
47
47
  "files": [
48
48
  "dist",