@openfn/ws-worker 1.6.6 → 1.7.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,22 @@
1
1
  # ws-worker
2
2
 
3
+ ## 1.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ae55a6a: Include timestamp on step complete even if the step failed
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [ae55a6a]
12
+ - @openfn/engine-multi@1.3.0
13
+
14
+ ## 1.6.7
15
+
16
+ ### Patch Changes
17
+
18
+ - 42883f8: Better handliung of claim backoffs when at capacity
19
+
3
20
  ## 1.6.6
4
21
 
5
22
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -8,6 +8,11 @@ import { ExecutionPlan, Lazy, State } from '@openfn/lexicon';
8
8
  import { Channel as Channel$1 } from 'phoenix';
9
9
  import { Server } from 'http';
10
10
 
11
+ declare type Workloop = {
12
+ stop: (reason?: string) => void;
13
+ isStopped: () => boolean;
14
+ };
15
+
11
16
  // Internal server state for each run
12
17
  type RunState = {
13
18
  activeStep?: string;
@@ -80,9 +85,10 @@ interface ServerApp extends Koa {
80
85
  server: Server;
81
86
  engine: RuntimeEngine;
82
87
  options: ServerOptions;
88
+ workloop?: Workloop;
83
89
  execute: ({ id, token }: ClaimRun) => Promise<void>;
84
90
  destroy: () => void;
85
- killWorkloop?: () => void;
91
+ resumeWorkloop: () => void;
86
92
  }
87
93
  declare function createServer(engine: RuntimeEngine, options?: ServerOptions): ServerApp;
88
94
 
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.6.6";
32
+ version = "1.7.0";
33
33
  description = "A Websocket Worker to connect Lightning to a Runtime Engine";
34
34
  main = "dist/index.js";
35
35
  type = "module";
@@ -132,7 +132,7 @@ var destroy = async (app, logger) => {
132
132
  await Promise.all([
133
133
  new Promise((resolve) => {
134
134
  app.destroyed = true;
135
- app.killWorkloop?.();
135
+ app.workloop?.stop("server closed");
136
136
  app.queueChannel?.leave();
137
137
  app.server.close(async () => {
138
138
  resolve();
@@ -232,9 +232,7 @@ var claim = (app, logger = mockLogger, options = {}) => {
232
232
  const { maxWorkers = 5 } = options;
233
233
  const activeWorkers = Object.keys(app.workflows).length;
234
234
  if (activeWorkers >= maxWorkers) {
235
- logger.debug(
236
- `skipping claim attempt: server at capacity (${activeWorkers}/${maxWorkers})`
237
- );
235
+ app.workloop?.stop(`server at capacity (${activeWorkers}/${maxWorkers})`);
238
236
  return reject(new Error("Server at capacity"));
239
237
  }
240
238
  if (!app.queueChannel) {
@@ -303,11 +301,15 @@ var startWorkloop = (app, logger, minBackoff, maxBackoff, maxWorkers) => {
303
301
  }
304
302
  };
305
303
  workLoop();
306
- return () => {
307
- logger.debug("cancelling workloop");
308
- cancelled = true;
309
- promise.cancel();
310
- app.queueChannel?.leave();
304
+ return {
305
+ stop: (reason = "reason unknown") => {
306
+ if (!cancelled) {
307
+ logger.info(`cancelling workloop: ${reason}`);
308
+ cancelled = true;
309
+ promise.cancel();
310
+ }
311
+ },
312
+ isStopped: () => cancelled
311
313
  };
312
314
  };
313
315
  var workloop_default = startWorkloop;
@@ -1018,16 +1020,7 @@ function connect(app, logger, options = {}) {
1018
1020
  logger.success("Connected to Lightning at", options.lightning);
1019
1021
  app.socket = socket;
1020
1022
  app.queueChannel = channel;
1021
- if (!options.noLoop) {
1022
- logger.info("Starting workloop");
1023
- app.killWorkloop = workloop_default(
1024
- app,
1025
- logger,
1026
- options.backoff?.min || MIN_BACKOFF,
1027
- options.backoff?.max || MAX_BACKOFF,
1028
- options.maxWorkflows
1029
- );
1030
- } else {
1023
+ if (options.noLoop) {
1031
1024
  const port = app.server?.address().port;
1032
1025
  logger.break();
1033
1026
  logger.warn("Noloop active: workloop has not started");
@@ -1036,17 +1029,17 @@ function connect(app, logger, options = {}) {
1036
1029
  logger.info(` curl -X POST http://localhost:${port}/claim`);
1037
1030
  logger.break();
1038
1031
  }
1032
+ app.resumeWorkloop();
1039
1033
  };
1040
1034
  const onDisconnect = () => {
1041
- if (app.killWorkloop) {
1042
- app.killWorkloop();
1043
- delete app.killWorkloop;
1044
- if (!app.destroyed) {
1045
- logger.info("Connection to lightning lost");
1046
- logger.info(
1047
- "Worker will automatically reconnect when lightning is back online"
1048
- );
1049
- }
1035
+ if (!app.workloop?.isStopped()) {
1036
+ app.workloop?.stop("Socket disconnected unexpectedly");
1037
+ }
1038
+ if (!app.destroyed) {
1039
+ logger.info("Connection to lightning lost");
1040
+ logger.info(
1041
+ "Worker will automatically reconnect when lightning is back online"
1042
+ );
1050
1043
  }
1051
1044
  };
1052
1045
  const onError = (e) => {
@@ -1089,6 +1082,21 @@ function createServer(engine, options = {}) {
1089
1082
  router.get("/livez", healthcheck_default);
1090
1083
  router.get("/", healthcheck_default);
1091
1084
  app.options = options;
1085
+ app.resumeWorkloop = () => {
1086
+ if (options.noLoop) {
1087
+ return;
1088
+ }
1089
+ if (!app.workloop || app.workloop?.isStopped()) {
1090
+ logger.info("Starting workloop");
1091
+ app.workloop = workloop_default(
1092
+ app,
1093
+ logger,
1094
+ options.backoff?.min || MIN_BACKOFF,
1095
+ options.backoff?.max || MAX_BACKOFF,
1096
+ options.maxWorkflows
1097
+ );
1098
+ }
1099
+ };
1092
1100
  app.execute = async ({ id, token }) => {
1093
1101
  if (app.socket) {
1094
1102
  try {
@@ -1111,6 +1119,7 @@ function createServer(engine, options = {}) {
1111
1119
  delete app.workflows[id];
1112
1120
  runChannel.leave();
1113
1121
  app.events.emit(INTERNAL_RUN_COMPLETE);
1122
+ app.resumeWorkloop();
1114
1123
  };
1115
1124
  const context = execute(
1116
1125
  runChannel,
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.6.6";
40
+ version = "1.7.0";
41
41
  description = "A Websocket Worker to connect Lightning to a Runtime Engine";
42
42
  main = "dist/index.js";
43
43
  type = "module";
@@ -271,7 +271,7 @@ var destroy = async (app, logger2) => {
271
271
  await Promise.all([
272
272
  new Promise((resolve5) => {
273
273
  app.destroyed = true;
274
- app.killWorkloop?.();
274
+ app.workloop?.stop("server closed");
275
275
  app.queueChannel?.leave();
276
276
  app.server.close(async () => {
277
277
  resolve5();
@@ -371,9 +371,7 @@ var claim = (app, logger2 = mockLogger, options = {}) => {
371
371
  const { maxWorkers = 5 } = options;
372
372
  const activeWorkers = Object.keys(app.workflows).length;
373
373
  if (activeWorkers >= maxWorkers) {
374
- logger2.debug(
375
- `skipping claim attempt: server at capacity (${activeWorkers}/${maxWorkers})`
376
- );
374
+ app.workloop?.stop(`server at capacity (${activeWorkers}/${maxWorkers})`);
377
375
  return reject(new Error("Server at capacity"));
378
376
  }
379
377
  if (!app.queueChannel) {
@@ -442,11 +440,15 @@ var startWorkloop = (app, logger2, minBackoff2, maxBackoff2, maxWorkers) => {
442
440
  }
443
441
  };
444
442
  workLoop();
445
- return () => {
446
- logger2.debug("cancelling workloop");
447
- cancelled = true;
448
- promise.cancel();
449
- app.queueChannel?.leave();
443
+ return {
444
+ stop: (reason = "reason unknown") => {
445
+ if (!cancelled) {
446
+ logger2.info(`cancelling workloop: ${reason}`);
447
+ cancelled = true;
448
+ promise.cancel();
449
+ }
450
+ },
451
+ isStopped: () => cancelled
450
452
  };
451
453
  };
452
454
  var workloop_default = startWorkloop;
@@ -1157,16 +1159,7 @@ function connect(app, logger2, options = {}) {
1157
1159
  logger2.success("Connected to Lightning at", options.lightning);
1158
1160
  app.socket = socket;
1159
1161
  app.queueChannel = channel;
1160
- if (!options.noLoop) {
1161
- logger2.info("Starting workloop");
1162
- app.killWorkloop = workloop_default(
1163
- app,
1164
- logger2,
1165
- options.backoff?.min || MIN_BACKOFF,
1166
- options.backoff?.max || MAX_BACKOFF,
1167
- options.maxWorkflows
1168
- );
1169
- } else {
1162
+ if (options.noLoop) {
1170
1163
  const port = app.server?.address().port;
1171
1164
  logger2.break();
1172
1165
  logger2.warn("Noloop active: workloop has not started");
@@ -1175,17 +1168,17 @@ function connect(app, logger2, options = {}) {
1175
1168
  logger2.info(` curl -X POST http://localhost:${port}/claim`);
1176
1169
  logger2.break();
1177
1170
  }
1171
+ app.resumeWorkloop();
1178
1172
  };
1179
1173
  const onDisconnect = () => {
1180
- if (app.killWorkloop) {
1181
- app.killWorkloop();
1182
- delete app.killWorkloop;
1183
- if (!app.destroyed) {
1184
- logger2.info("Connection to lightning lost");
1185
- logger2.info(
1186
- "Worker will automatically reconnect when lightning is back online"
1187
- );
1188
- }
1174
+ if (!app.workloop?.isStopped()) {
1175
+ app.workloop?.stop("Socket disconnected unexpectedly");
1176
+ }
1177
+ if (!app.destroyed) {
1178
+ logger2.info("Connection to lightning lost");
1179
+ logger2.info(
1180
+ "Worker will automatically reconnect when lightning is back online"
1181
+ );
1189
1182
  }
1190
1183
  };
1191
1184
  const onError = (e) => {
@@ -1228,6 +1221,21 @@ function createServer(engine, options = {}) {
1228
1221
  router.get("/livez", healthcheck_default);
1229
1222
  router.get("/", healthcheck_default);
1230
1223
  app.options = options;
1224
+ app.resumeWorkloop = () => {
1225
+ if (options.noLoop) {
1226
+ return;
1227
+ }
1228
+ if (!app.workloop || app.workloop?.isStopped()) {
1229
+ logger2.info("Starting workloop");
1230
+ app.workloop = workloop_default(
1231
+ app,
1232
+ logger2,
1233
+ options.backoff?.min || MIN_BACKOFF,
1234
+ options.backoff?.max || MAX_BACKOFF,
1235
+ options.maxWorkflows
1236
+ );
1237
+ }
1238
+ };
1231
1239
  app.execute = async ({ id, token }) => {
1232
1240
  if (app.socket) {
1233
1241
  try {
@@ -1250,6 +1258,7 @@ function createServer(engine, options = {}) {
1250
1258
  delete app.workflows[id];
1251
1259
  runChannel.leave();
1252
1260
  app.events.emit(INTERNAL_RUN_COMPLETE);
1261
+ app.resumeWorkloop();
1253
1262
  };
1254
1263
  const context = execute(
1255
1264
  runChannel,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfn/ws-worker",
3
- "version": "1.6.6",
3
+ "version": "1.7.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,8 +22,8 @@
22
22
  "koa-logger": "^3.2.1",
23
23
  "phoenix": "1.7.10",
24
24
  "ws": "^8.18.0",
25
- "@openfn/engine-multi": "1.2.5",
26
25
  "@openfn/lexicon": "^1.1.0",
26
+ "@openfn/engine-multi": "1.3.0",
27
27
  "@openfn/runtime": "1.4.2",
28
28
  "@openfn/logger": "1.0.2"
29
29
  },
@@ -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.19"
45
+ "@openfn/lightning-mock": "2.0.20"
46
46
  },
47
47
  "files": [
48
48
  "dist",