@openfn/ws-worker 1.14.0 → 1.14.2
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 +16 -0
- package/dist/index.js +62 -27
- package/dist/start.js +68 -31
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# ws-worker
|
|
2
2
|
|
|
3
|
+
## 1.14.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [f04acef]
|
|
8
|
+
- @openfn/runtime@1.7.1
|
|
9
|
+
- @openfn/engine-multi@1.6.8
|
|
10
|
+
|
|
11
|
+
## 1.14.1
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- d765843: Fix an issue where the server can attempt to claim even while it's waiting to shut down
|
|
16
|
+
- 667e3bf: Improve logging of errors returned by lightning
|
|
17
|
+
- d765843: Fix an issue where the --backoff server argument only accepts integer values
|
|
18
|
+
|
|
3
19
|
## 1.14.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
3
3
|
import { promisify } from "node:util";
|
|
4
4
|
import { exec as _exec } from "node:child_process";
|
|
5
|
-
import * as
|
|
5
|
+
import * as Sentry6 from "@sentry/node";
|
|
6
6
|
import Koa from "koa";
|
|
7
7
|
import bodyParser from "koa-bodyparser";
|
|
8
8
|
import koaLogger from "koa-logger";
|
|
@@ -82,6 +82,10 @@ var tryWithBackoff = (fn, opts = {}) => {
|
|
|
82
82
|
await fn();
|
|
83
83
|
resolve();
|
|
84
84
|
} catch (e) {
|
|
85
|
+
if (e?.abort) {
|
|
86
|
+
cancelled = true;
|
|
87
|
+
return reject();
|
|
88
|
+
}
|
|
85
89
|
if (opts.isCancelled()) {
|
|
86
90
|
return resolve();
|
|
87
91
|
}
|
|
@@ -111,6 +115,7 @@ var tryWithBackoff = (fn, opts = {}) => {
|
|
|
111
115
|
var try_with_backoff_default = tryWithBackoff;
|
|
112
116
|
|
|
113
117
|
// src/api/claim.ts
|
|
118
|
+
import * as Sentry from "@sentry/node";
|
|
114
119
|
import crypto from "node:crypto";
|
|
115
120
|
import * as jose from "jose";
|
|
116
121
|
import { createMockLogger } from "@openfn/logger";
|
|
@@ -128,6 +133,13 @@ var verifyToken = async (token, publicKey) => {
|
|
|
128
133
|
};
|
|
129
134
|
var { DEPLOYED_POD_NAME, WORKER_NAME } = process.env;
|
|
130
135
|
var NAME = WORKER_NAME || DEPLOYED_POD_NAME;
|
|
136
|
+
var ClaimError = class extends Error {
|
|
137
|
+
constructor(e) {
|
|
138
|
+
super(e);
|
|
139
|
+
// This breaks the parenting backoff loop
|
|
140
|
+
this.abort = true;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
131
143
|
var claim = (app, logger = mockLogger, options = {}) => {
|
|
132
144
|
return new Promise((resolve, reject) => {
|
|
133
145
|
const { maxWorkers = 5 } = options;
|
|
@@ -135,11 +147,17 @@ var claim = (app, logger = mockLogger, options = {}) => {
|
|
|
135
147
|
const activeWorkers = Object.keys(app.workflows).length;
|
|
136
148
|
if (activeWorkers >= maxWorkers) {
|
|
137
149
|
app.workloop?.stop(`server at capacity (${activeWorkers}/${maxWorkers})`);
|
|
138
|
-
return reject(new
|
|
150
|
+
return reject(new ClaimError("Server at capacity"));
|
|
139
151
|
}
|
|
140
152
|
if (!app.queueChannel) {
|
|
141
|
-
logger.
|
|
142
|
-
return reject(new
|
|
153
|
+
logger.warn("skipping claim attempt: websocket unavailable");
|
|
154
|
+
return reject(new ClaimError("No websocket available"));
|
|
155
|
+
}
|
|
156
|
+
if (app.queueChannel.state === "closed") {
|
|
157
|
+
const e = new ClaimError("queue closed");
|
|
158
|
+
Sentry.captureException(e);
|
|
159
|
+
logger.warn("skipping claim attempt: channel closed");
|
|
160
|
+
return reject(e);
|
|
143
161
|
}
|
|
144
162
|
logger.debug(`requesting run (capacity ${activeWorkers}/${maxWorkers})`);
|
|
145
163
|
const start = Date.now();
|
|
@@ -202,6 +220,7 @@ var startWorkloop = (app, logger, minBackoff, maxBackoff, maxWorkers) => {
|
|
|
202
220
|
if (!cancelled) {
|
|
203
221
|
setTimeout(workLoop, minBackoff);
|
|
204
222
|
}
|
|
223
|
+
}).catch(() => {
|
|
205
224
|
});
|
|
206
225
|
}
|
|
207
226
|
};
|
|
@@ -220,7 +239,7 @@ var startWorkloop = (app, logger, minBackoff, maxBackoff, maxWorkers) => {
|
|
|
220
239
|
var workloop_default = startWorkloop;
|
|
221
240
|
|
|
222
241
|
// src/api/execute.ts
|
|
223
|
-
import * as
|
|
242
|
+
import * as Sentry3 from "@sentry/node";
|
|
224
243
|
|
|
225
244
|
// src/util/convert-lightning-plan.ts
|
|
226
245
|
import crypto2 from "node:crypto";
|
|
@@ -435,12 +454,28 @@ var create_run_state_default = (plan, input) => {
|
|
|
435
454
|
};
|
|
436
455
|
|
|
437
456
|
// src/util/send-event.ts
|
|
438
|
-
import * as
|
|
457
|
+
import * as Sentry2 from "@sentry/node";
|
|
439
458
|
|
|
440
459
|
// src/errors.ts
|
|
460
|
+
function serializeMessage(message) {
|
|
461
|
+
if (typeof message === "string") {
|
|
462
|
+
return message;
|
|
463
|
+
}
|
|
464
|
+
if (message instanceof Error) {
|
|
465
|
+
return message.toString();
|
|
466
|
+
}
|
|
467
|
+
if (message && typeof message === "object") {
|
|
468
|
+
try {
|
|
469
|
+
return JSON.stringify(message);
|
|
470
|
+
} catch {
|
|
471
|
+
return String(message);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return String(message);
|
|
475
|
+
}
|
|
441
476
|
var LightningSocketError = class extends Error {
|
|
442
477
|
constructor(event, message) {
|
|
443
|
-
super(`[${event}] ${message}`);
|
|
478
|
+
super(`[${event}] ${serializeMessage(message)}`);
|
|
444
479
|
this.name = "LightningSocketError";
|
|
445
480
|
this.event = "";
|
|
446
481
|
this.rejectMessage = "";
|
|
@@ -469,7 +504,7 @@ var sendEvent = (context, event, payload) => {
|
|
|
469
504
|
if (error.rejectMessage) {
|
|
470
505
|
extras.rejection_reason = error.rejectMessage;
|
|
471
506
|
}
|
|
472
|
-
|
|
507
|
+
Sentry2.captureException(error, (scope) => {
|
|
473
508
|
scope.setContext("run", context2);
|
|
474
509
|
scope.setExtras(extras);
|
|
475
510
|
return scope;
|
|
@@ -802,8 +837,8 @@ function execute(channel, engine, logger, plan, input, options = {}, onFinish =
|
|
|
802
837
|
options,
|
|
803
838
|
onFinish
|
|
804
839
|
};
|
|
805
|
-
|
|
806
|
-
|
|
840
|
+
Sentry3.withIsolationScope(async () => {
|
|
841
|
+
Sentry3.addBreadcrumb({
|
|
807
842
|
category: "run",
|
|
808
843
|
message: "Executing run: loading metadata",
|
|
809
844
|
level: "info",
|
|
@@ -815,7 +850,7 @@ function execute(channel, engine, logger, plan, input, options = {}, onFinish =
|
|
|
815
850
|
const addEvent = (eventName, handler) => {
|
|
816
851
|
const wrappedFn = async (event) => {
|
|
817
852
|
if (eventName !== "workflow-log") {
|
|
818
|
-
|
|
853
|
+
Sentry3.addBreadcrumb({
|
|
819
854
|
category: "event",
|
|
820
855
|
message: eventName,
|
|
821
856
|
level: "info"
|
|
@@ -827,7 +862,7 @@ function execute(channel, engine, logger, plan, input, options = {}, onFinish =
|
|
|
827
862
|
logger.info(`${plan.id} :: ${lightningEvent} :: OK`);
|
|
828
863
|
} catch (e) {
|
|
829
864
|
if (!e.reportedToSentry) {
|
|
830
|
-
|
|
865
|
+
Sentry3.captureException(e);
|
|
831
866
|
logger.error(e);
|
|
832
867
|
}
|
|
833
868
|
}
|
|
@@ -871,7 +906,7 @@ function execute(channel, engine, logger, plan, input, options = {}, onFinish =
|
|
|
871
906
|
}
|
|
872
907
|
}
|
|
873
908
|
try {
|
|
874
|
-
|
|
909
|
+
Sentry3.addBreadcrumb({
|
|
875
910
|
category: "run",
|
|
876
911
|
message: "run metadata loaded: starting run",
|
|
877
912
|
level: "info",
|
|
@@ -881,7 +916,7 @@ function execute(channel, engine, logger, plan, input, options = {}, onFinish =
|
|
|
881
916
|
});
|
|
882
917
|
engine.execute(plan, loadedInput, { resolvers, ...options });
|
|
883
918
|
} catch (e) {
|
|
884
|
-
|
|
919
|
+
Sentry3.addBreadcrumb({
|
|
885
920
|
category: "run",
|
|
886
921
|
message: "exception in run",
|
|
887
922
|
level: "info",
|
|
@@ -948,7 +983,7 @@ var healthcheck_default = (ctx) => {
|
|
|
948
983
|
};
|
|
949
984
|
|
|
950
985
|
// src/channels/run.ts
|
|
951
|
-
import * as
|
|
986
|
+
import * as Sentry4 from "@sentry/node";
|
|
952
987
|
var joinRunChannel = (socket, token, runId, logger, timeout = 30) => {
|
|
953
988
|
return new Promise((resolve, reject) => {
|
|
954
989
|
let didReceiveOk = false;
|
|
@@ -967,12 +1002,12 @@ var joinRunChannel = (socket, token, runId, logger, timeout = 30) => {
|
|
|
967
1002
|
resolve({ channel, run });
|
|
968
1003
|
}
|
|
969
1004
|
}).receive("error", (err) => {
|
|
970
|
-
|
|
1005
|
+
Sentry4.captureException(err);
|
|
971
1006
|
logger.error(`error connecting to ${channelName}`, err);
|
|
972
1007
|
channel?.leave();
|
|
973
1008
|
reject(err);
|
|
974
1009
|
}).receive("timeout", (err) => {
|
|
975
|
-
|
|
1010
|
+
Sentry4.captureException(err);
|
|
976
1011
|
logger.error(`Timeout for ${channelName}`, err);
|
|
977
1012
|
channel?.leave();
|
|
978
1013
|
reject(err);
|
|
@@ -990,7 +1025,7 @@ var run_default = joinRunChannel;
|
|
|
990
1025
|
|
|
991
1026
|
// src/channels/worker-queue.ts
|
|
992
1027
|
import EventEmitter from "node:events";
|
|
993
|
-
import * as
|
|
1028
|
+
import * as Sentry5 from "@sentry/node";
|
|
994
1029
|
import { Socket as PhxSocket } from "phoenix";
|
|
995
1030
|
import { WebSocket } from "ws";
|
|
996
1031
|
import { API_VERSION } from "@openfn/lexicon/lightning";
|
|
@@ -1019,13 +1054,13 @@ var worker_token_default = generateWorkerToken;
|
|
|
1019
1054
|
// src/channels/worker-queue.ts
|
|
1020
1055
|
var connectToWorkerQueue = (endpoint, serverId, secret, timeout = 10, logger, SocketConstructor = PhxSocket) => {
|
|
1021
1056
|
const events = new EventEmitter();
|
|
1022
|
-
|
|
1057
|
+
Sentry5.addBreadcrumb({
|
|
1023
1058
|
category: "lifecycle",
|
|
1024
1059
|
message: "Connecting to worker queue",
|
|
1025
1060
|
level: "info"
|
|
1026
1061
|
});
|
|
1027
1062
|
worker_token_default(secret, serverId, logger).then(async (token) => {
|
|
1028
|
-
|
|
1063
|
+
Sentry5.addBreadcrumb({
|
|
1029
1064
|
category: "lifecycle",
|
|
1030
1065
|
message: "Worker token generated",
|
|
1031
1066
|
level: "info"
|
|
@@ -1044,7 +1079,7 @@ var connectToWorkerQueue = (endpoint, serverId, secret, timeout = 10, logger, So
|
|
|
1044
1079
|
let didOpen = false;
|
|
1045
1080
|
let shouldReportConnectionError = true;
|
|
1046
1081
|
socket.onOpen(() => {
|
|
1047
|
-
|
|
1082
|
+
Sentry5.addBreadcrumb({
|
|
1048
1083
|
category: "lifecycle",
|
|
1049
1084
|
message: "Web socket connected",
|
|
1050
1085
|
level: "info"
|
|
@@ -1070,7 +1105,7 @@ var connectToWorkerQueue = (endpoint, serverId, secret, timeout = 10, logger, So
|
|
|
1070
1105
|
events.emit("disconnect");
|
|
1071
1106
|
});
|
|
1072
1107
|
socket.onError((e) => {
|
|
1073
|
-
|
|
1108
|
+
Sentry5.addBreadcrumb({
|
|
1074
1109
|
category: "lifecycle",
|
|
1075
1110
|
message: "Error in web socket connection",
|
|
1076
1111
|
level: "info"
|
|
@@ -1078,7 +1113,7 @@ var connectToWorkerQueue = (endpoint, serverId, secret, timeout = 10, logger, So
|
|
|
1078
1113
|
if (shouldReportConnectionError) {
|
|
1079
1114
|
logger.debug("Reporting connection error to sentry");
|
|
1080
1115
|
shouldReportConnectionError = false;
|
|
1081
|
-
|
|
1116
|
+
Sentry5.captureException(e);
|
|
1082
1117
|
}
|
|
1083
1118
|
if (!didOpen) {
|
|
1084
1119
|
events.emit("error", e.message);
|
|
@@ -1185,11 +1220,11 @@ function createServer(engine, options = {}) {
|
|
|
1185
1220
|
app.events = new EventEmitter2();
|
|
1186
1221
|
app.engine = engine;
|
|
1187
1222
|
if (options.sentryDsn) {
|
|
1188
|
-
|
|
1223
|
+
Sentry6.init({
|
|
1189
1224
|
environment: options.sentryEnv,
|
|
1190
1225
|
dsn: options.sentryDsn
|
|
1191
1226
|
});
|
|
1192
|
-
|
|
1227
|
+
Sentry6.setupKoaErrorHandler(app);
|
|
1193
1228
|
}
|
|
1194
1229
|
app.use(bodyParser());
|
|
1195
1230
|
app.use(
|
|
@@ -1206,7 +1241,7 @@ function createServer(engine, options = {}) {
|
|
|
1206
1241
|
router.get("/", healthcheck_default);
|
|
1207
1242
|
app.options = options;
|
|
1208
1243
|
app.resumeWorkloop = () => {
|
|
1209
|
-
if (options.noLoop) {
|
|
1244
|
+
if (options.noLoop || app.destroyed) {
|
|
1210
1245
|
return;
|
|
1211
1246
|
}
|
|
1212
1247
|
if (!app.workloop || app.workloop?.isStopped()) {
|
|
@@ -1306,7 +1341,7 @@ function createServer(engine, options = {}) {
|
|
|
1306
1341
|
shutdown = true;
|
|
1307
1342
|
logger.always(`${signal} RECEIVED: CLOSING SERVER`);
|
|
1308
1343
|
await app.destroy();
|
|
1309
|
-
process.exit();
|
|
1344
|
+
process.exit(0);
|
|
1310
1345
|
}
|
|
1311
1346
|
};
|
|
1312
1347
|
process.on("SIGINT", () => exit("SIGINT"));
|
package/dist/start.js
CHANGED
|
@@ -142,7 +142,7 @@ var runtime_engine_default = createMock;
|
|
|
142
142
|
import { EventEmitter as EventEmitter3 } from "node:events";
|
|
143
143
|
import { promisify } from "node:util";
|
|
144
144
|
import { exec as _exec } from "node:child_process";
|
|
145
|
-
import * as
|
|
145
|
+
import * as Sentry6 from "@sentry/node";
|
|
146
146
|
import Koa from "koa";
|
|
147
147
|
import bodyParser from "koa-bodyparser";
|
|
148
148
|
import koaLogger from "koa-logger";
|
|
@@ -222,6 +222,10 @@ var tryWithBackoff = (fn, opts = {}) => {
|
|
|
222
222
|
await fn();
|
|
223
223
|
resolve5();
|
|
224
224
|
} catch (e) {
|
|
225
|
+
if (e?.abort) {
|
|
226
|
+
cancelled = true;
|
|
227
|
+
return reject();
|
|
228
|
+
}
|
|
225
229
|
if (opts.isCancelled()) {
|
|
226
230
|
return resolve5();
|
|
227
231
|
}
|
|
@@ -251,6 +255,7 @@ var tryWithBackoff = (fn, opts = {}) => {
|
|
|
251
255
|
var try_with_backoff_default = tryWithBackoff;
|
|
252
256
|
|
|
253
257
|
// src/api/claim.ts
|
|
258
|
+
import * as Sentry from "@sentry/node";
|
|
254
259
|
import crypto2 from "node:crypto";
|
|
255
260
|
import * as jose from "jose";
|
|
256
261
|
import { createMockLogger } from "@openfn/logger";
|
|
@@ -268,6 +273,13 @@ var verifyToken = async (token, publicKey) => {
|
|
|
268
273
|
};
|
|
269
274
|
var { DEPLOYED_POD_NAME, WORKER_NAME } = process.env;
|
|
270
275
|
var NAME = WORKER_NAME || DEPLOYED_POD_NAME;
|
|
276
|
+
var ClaimError = class extends Error {
|
|
277
|
+
constructor(e) {
|
|
278
|
+
super(e);
|
|
279
|
+
// This breaks the parenting backoff loop
|
|
280
|
+
this.abort = true;
|
|
281
|
+
}
|
|
282
|
+
};
|
|
271
283
|
var claim = (app, logger2 = mockLogger, options = {}) => {
|
|
272
284
|
return new Promise((resolve5, reject) => {
|
|
273
285
|
const { maxWorkers = 5 } = options;
|
|
@@ -275,11 +287,17 @@ var claim = (app, logger2 = mockLogger, options = {}) => {
|
|
|
275
287
|
const activeWorkers = Object.keys(app.workflows).length;
|
|
276
288
|
if (activeWorkers >= maxWorkers) {
|
|
277
289
|
app.workloop?.stop(`server at capacity (${activeWorkers}/${maxWorkers})`);
|
|
278
|
-
return reject(new
|
|
290
|
+
return reject(new ClaimError("Server at capacity"));
|
|
279
291
|
}
|
|
280
292
|
if (!app.queueChannel) {
|
|
281
|
-
logger2.
|
|
282
|
-
return reject(new
|
|
293
|
+
logger2.warn("skipping claim attempt: websocket unavailable");
|
|
294
|
+
return reject(new ClaimError("No websocket available"));
|
|
295
|
+
}
|
|
296
|
+
if (app.queueChannel.state === "closed") {
|
|
297
|
+
const e = new ClaimError("queue closed");
|
|
298
|
+
Sentry.captureException(e);
|
|
299
|
+
logger2.warn("skipping claim attempt: channel closed");
|
|
300
|
+
return reject(e);
|
|
283
301
|
}
|
|
284
302
|
logger2.debug(`requesting run (capacity ${activeWorkers}/${maxWorkers})`);
|
|
285
303
|
const start = Date.now();
|
|
@@ -342,6 +360,7 @@ var startWorkloop = (app, logger2, minBackoff2, maxBackoff2, maxWorkers) => {
|
|
|
342
360
|
if (!cancelled) {
|
|
343
361
|
setTimeout(workLoop, minBackoff2);
|
|
344
362
|
}
|
|
363
|
+
}).catch(() => {
|
|
345
364
|
});
|
|
346
365
|
}
|
|
347
366
|
};
|
|
@@ -360,7 +379,7 @@ var startWorkloop = (app, logger2, minBackoff2, maxBackoff2, maxWorkers) => {
|
|
|
360
379
|
var workloop_default = startWorkloop;
|
|
361
380
|
|
|
362
381
|
// src/api/execute.ts
|
|
363
|
-
import * as
|
|
382
|
+
import * as Sentry3 from "@sentry/node";
|
|
364
383
|
|
|
365
384
|
// src/util/convert-lightning-plan.ts
|
|
366
385
|
import crypto3 from "node:crypto";
|
|
@@ -575,12 +594,28 @@ var create_run_state_default = (plan, input) => {
|
|
|
575
594
|
};
|
|
576
595
|
|
|
577
596
|
// src/util/send-event.ts
|
|
578
|
-
import * as
|
|
597
|
+
import * as Sentry2 from "@sentry/node";
|
|
579
598
|
|
|
580
599
|
// src/errors.ts
|
|
600
|
+
function serializeMessage(message) {
|
|
601
|
+
if (typeof message === "string") {
|
|
602
|
+
return message;
|
|
603
|
+
}
|
|
604
|
+
if (message instanceof Error) {
|
|
605
|
+
return message.toString();
|
|
606
|
+
}
|
|
607
|
+
if (message && typeof message === "object") {
|
|
608
|
+
try {
|
|
609
|
+
return JSON.stringify(message);
|
|
610
|
+
} catch {
|
|
611
|
+
return String(message);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return String(message);
|
|
615
|
+
}
|
|
581
616
|
var LightningSocketError = class extends Error {
|
|
582
617
|
constructor(event, message) {
|
|
583
|
-
super(`[${event}] ${message}`);
|
|
618
|
+
super(`[${event}] ${serializeMessage(message)}`);
|
|
584
619
|
this.name = "LightningSocketError";
|
|
585
620
|
this.event = "";
|
|
586
621
|
this.rejectMessage = "";
|
|
@@ -609,7 +644,7 @@ var sendEvent = (context, event, payload) => {
|
|
|
609
644
|
if (error.rejectMessage) {
|
|
610
645
|
extras.rejection_reason = error.rejectMessage;
|
|
611
646
|
}
|
|
612
|
-
|
|
647
|
+
Sentry2.captureException(error, (scope) => {
|
|
613
648
|
scope.setContext("run", context2);
|
|
614
649
|
scope.setExtras(extras);
|
|
615
650
|
return scope;
|
|
@@ -942,8 +977,8 @@ function execute(channel, engine, logger2, plan, input, options = {}, onFinish =
|
|
|
942
977
|
options,
|
|
943
978
|
onFinish
|
|
944
979
|
};
|
|
945
|
-
|
|
946
|
-
|
|
980
|
+
Sentry3.withIsolationScope(async () => {
|
|
981
|
+
Sentry3.addBreadcrumb({
|
|
947
982
|
category: "run",
|
|
948
983
|
message: "Executing run: loading metadata",
|
|
949
984
|
level: "info",
|
|
@@ -955,7 +990,7 @@ function execute(channel, engine, logger2, plan, input, options = {}, onFinish =
|
|
|
955
990
|
const addEvent = (eventName, handler) => {
|
|
956
991
|
const wrappedFn = async (event) => {
|
|
957
992
|
if (eventName !== "workflow-log") {
|
|
958
|
-
|
|
993
|
+
Sentry3.addBreadcrumb({
|
|
959
994
|
category: "event",
|
|
960
995
|
message: eventName,
|
|
961
996
|
level: "info"
|
|
@@ -967,7 +1002,7 @@ function execute(channel, engine, logger2, plan, input, options = {}, onFinish =
|
|
|
967
1002
|
logger2.info(`${plan.id} :: ${lightningEvent} :: OK`);
|
|
968
1003
|
} catch (e) {
|
|
969
1004
|
if (!e.reportedToSentry) {
|
|
970
|
-
|
|
1005
|
+
Sentry3.captureException(e);
|
|
971
1006
|
logger2.error(e);
|
|
972
1007
|
}
|
|
973
1008
|
}
|
|
@@ -1011,7 +1046,7 @@ function execute(channel, engine, logger2, plan, input, options = {}, onFinish =
|
|
|
1011
1046
|
}
|
|
1012
1047
|
}
|
|
1013
1048
|
try {
|
|
1014
|
-
|
|
1049
|
+
Sentry3.addBreadcrumb({
|
|
1015
1050
|
category: "run",
|
|
1016
1051
|
message: "run metadata loaded: starting run",
|
|
1017
1052
|
level: "info",
|
|
@@ -1021,7 +1056,7 @@ function execute(channel, engine, logger2, plan, input, options = {}, onFinish =
|
|
|
1021
1056
|
});
|
|
1022
1057
|
engine.execute(plan, loadedInput, { resolvers, ...options });
|
|
1023
1058
|
} catch (e) {
|
|
1024
|
-
|
|
1059
|
+
Sentry3.addBreadcrumb({
|
|
1025
1060
|
category: "run",
|
|
1026
1061
|
message: "exception in run",
|
|
1027
1062
|
level: "info",
|
|
@@ -1088,7 +1123,7 @@ var healthcheck_default = (ctx) => {
|
|
|
1088
1123
|
};
|
|
1089
1124
|
|
|
1090
1125
|
// src/channels/run.ts
|
|
1091
|
-
import * as
|
|
1126
|
+
import * as Sentry4 from "@sentry/node";
|
|
1092
1127
|
var joinRunChannel = (socket, token, runId, logger2, timeout = 30) => {
|
|
1093
1128
|
return new Promise((resolve5, reject) => {
|
|
1094
1129
|
let didReceiveOk = false;
|
|
@@ -1107,12 +1142,12 @@ var joinRunChannel = (socket, token, runId, logger2, timeout = 30) => {
|
|
|
1107
1142
|
resolve5({ channel, run: run2 });
|
|
1108
1143
|
}
|
|
1109
1144
|
}).receive("error", (err) => {
|
|
1110
|
-
|
|
1145
|
+
Sentry4.captureException(err);
|
|
1111
1146
|
logger2.error(`error connecting to ${channelName}`, err);
|
|
1112
1147
|
channel?.leave();
|
|
1113
1148
|
reject(err);
|
|
1114
1149
|
}).receive("timeout", (err) => {
|
|
1115
|
-
|
|
1150
|
+
Sentry4.captureException(err);
|
|
1116
1151
|
logger2.error(`Timeout for ${channelName}`, err);
|
|
1117
1152
|
channel?.leave();
|
|
1118
1153
|
reject(err);
|
|
@@ -1130,7 +1165,7 @@ var run_default = joinRunChannel;
|
|
|
1130
1165
|
|
|
1131
1166
|
// src/channels/worker-queue.ts
|
|
1132
1167
|
import EventEmitter2 from "node:events";
|
|
1133
|
-
import * as
|
|
1168
|
+
import * as Sentry5 from "@sentry/node";
|
|
1134
1169
|
import { Socket as PhxSocket } from "phoenix";
|
|
1135
1170
|
import { WebSocket } from "ws";
|
|
1136
1171
|
import { API_VERSION } from "@openfn/lexicon/lightning";
|
|
@@ -1159,13 +1194,13 @@ var worker_token_default = generateWorkerToken;
|
|
|
1159
1194
|
// src/channels/worker-queue.ts
|
|
1160
1195
|
var connectToWorkerQueue = (endpoint, serverId, secret, timeout = 10, logger2, SocketConstructor = PhxSocket) => {
|
|
1161
1196
|
const events = new EventEmitter2();
|
|
1162
|
-
|
|
1197
|
+
Sentry5.addBreadcrumb({
|
|
1163
1198
|
category: "lifecycle",
|
|
1164
1199
|
message: "Connecting to worker queue",
|
|
1165
1200
|
level: "info"
|
|
1166
1201
|
});
|
|
1167
1202
|
worker_token_default(secret, serverId, logger2).then(async (token) => {
|
|
1168
|
-
|
|
1203
|
+
Sentry5.addBreadcrumb({
|
|
1169
1204
|
category: "lifecycle",
|
|
1170
1205
|
message: "Worker token generated",
|
|
1171
1206
|
level: "info"
|
|
@@ -1184,7 +1219,7 @@ var connectToWorkerQueue = (endpoint, serverId, secret, timeout = 10, logger2, S
|
|
|
1184
1219
|
let didOpen = false;
|
|
1185
1220
|
let shouldReportConnectionError = true;
|
|
1186
1221
|
socket.onOpen(() => {
|
|
1187
|
-
|
|
1222
|
+
Sentry5.addBreadcrumb({
|
|
1188
1223
|
category: "lifecycle",
|
|
1189
1224
|
message: "Web socket connected",
|
|
1190
1225
|
level: "info"
|
|
@@ -1210,7 +1245,7 @@ var connectToWorkerQueue = (endpoint, serverId, secret, timeout = 10, logger2, S
|
|
|
1210
1245
|
events.emit("disconnect");
|
|
1211
1246
|
});
|
|
1212
1247
|
socket.onError((e) => {
|
|
1213
|
-
|
|
1248
|
+
Sentry5.addBreadcrumb({
|
|
1214
1249
|
category: "lifecycle",
|
|
1215
1250
|
message: "Error in web socket connection",
|
|
1216
1251
|
level: "info"
|
|
@@ -1218,7 +1253,7 @@ var connectToWorkerQueue = (endpoint, serverId, secret, timeout = 10, logger2, S
|
|
|
1218
1253
|
if (shouldReportConnectionError) {
|
|
1219
1254
|
logger2.debug("Reporting connection error to sentry");
|
|
1220
1255
|
shouldReportConnectionError = false;
|
|
1221
|
-
|
|
1256
|
+
Sentry5.captureException(e);
|
|
1222
1257
|
}
|
|
1223
1258
|
if (!didOpen) {
|
|
1224
1259
|
events.emit("error", e.message);
|
|
@@ -1325,11 +1360,11 @@ function createServer(engine, options = {}) {
|
|
|
1325
1360
|
app.events = new EventEmitter3();
|
|
1326
1361
|
app.engine = engine;
|
|
1327
1362
|
if (options.sentryDsn) {
|
|
1328
|
-
|
|
1363
|
+
Sentry6.init({
|
|
1329
1364
|
environment: options.sentryEnv,
|
|
1330
1365
|
dsn: options.sentryDsn
|
|
1331
1366
|
});
|
|
1332
|
-
|
|
1367
|
+
Sentry6.setupKoaErrorHandler(app);
|
|
1333
1368
|
}
|
|
1334
1369
|
app.use(bodyParser());
|
|
1335
1370
|
app.use(
|
|
@@ -1346,7 +1381,7 @@ function createServer(engine, options = {}) {
|
|
|
1346
1381
|
router.get("/", healthcheck_default);
|
|
1347
1382
|
app.options = options;
|
|
1348
1383
|
app.resumeWorkloop = () => {
|
|
1349
|
-
if (options.noLoop) {
|
|
1384
|
+
if (options.noLoop || app.destroyed) {
|
|
1350
1385
|
return;
|
|
1351
1386
|
}
|
|
1352
1387
|
if (!app.workloop || app.workloop?.isStopped()) {
|
|
@@ -1446,7 +1481,7 @@ function createServer(engine, options = {}) {
|
|
|
1446
1481
|
shutdown = true;
|
|
1447
1482
|
logger2.always(`${signal} RECEIVED: CLOSING SERVER`);
|
|
1448
1483
|
await app.destroy();
|
|
1449
|
-
process.exit();
|
|
1484
|
+
process.exit(0);
|
|
1450
1485
|
}
|
|
1451
1486
|
};
|
|
1452
1487
|
process.on("SIGINT", () => exit("SIGINT"));
|
|
@@ -6350,7 +6385,10 @@ function parseArgs(argv) {
|
|
|
6350
6385
|
WORKER_SOCKET_TIMEOUT_SECONDS,
|
|
6351
6386
|
WORKER_STATE_PROPS_TO_REMOVE
|
|
6352
6387
|
} = process.env;
|
|
6353
|
-
const parser2 = yargs_default(hideBin(argv)).command("server", "Start a ws-worker server").option("
|
|
6388
|
+
const parser2 = yargs_default(hideBin(argv)).command("server", "Start a ws-worker server").option("debug", {
|
|
6389
|
+
hidden: true,
|
|
6390
|
+
type: "boolean"
|
|
6391
|
+
}).option("port", {
|
|
6354
6392
|
alias: "p",
|
|
6355
6393
|
description: `Port to run the server on. Default ${DEFAULT_PORT2}. Env: WORKER_PORT`,
|
|
6356
6394
|
type: "number"
|
|
@@ -6472,11 +6510,11 @@ if (args.lightning === "mock") {
|
|
|
6472
6510
|
if (!args.secret) {
|
|
6473
6511
|
args.secret = "abdefg";
|
|
6474
6512
|
}
|
|
6475
|
-
} else if (!args.secret) {
|
|
6513
|
+
} else if (!args.debug && !args.secret) {
|
|
6476
6514
|
logger.error("WORKER_SECRET is not set");
|
|
6477
6515
|
process.exit(1);
|
|
6478
6516
|
}
|
|
6479
|
-
var [minBackoff, maxBackoff] = args.backoff.split("/").map((n) =>
|
|
6517
|
+
var [minBackoff, maxBackoff] = args.backoff.split("/").map((n) => parseFloat(n) * 1e3);
|
|
6480
6518
|
function engineReady(engine) {
|
|
6481
6519
|
logger.debug("Creating worker instance");
|
|
6482
6520
|
const workerOptions = {
|
|
@@ -6487,7 +6525,6 @@ function engineReady(engine) {
|
|
|
6487
6525
|
sentryDsn: args.sentryDsn,
|
|
6488
6526
|
sentryEnv: args.sentryEnv,
|
|
6489
6527
|
noLoop: !args.loop,
|
|
6490
|
-
// TODO need to feed this through properly
|
|
6491
6528
|
backoff: {
|
|
6492
6529
|
min: minBackoff,
|
|
6493
6530
|
max: maxBackoff
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfn/ws-worker",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.2",
|
|
4
4
|
"description": "A Websocket Worker to connect Lightning to a Runtime Engine",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
"koa-logger": "^3.2.1",
|
|
24
24
|
"phoenix": "1.7.10",
|
|
25
25
|
"ws": "^8.18.0",
|
|
26
|
-
"@openfn/engine-multi": "1.6.
|
|
26
|
+
"@openfn/engine-multi": "1.6.8",
|
|
27
27
|
"@openfn/lexicon": "^1.2.2",
|
|
28
|
-
"@openfn/
|
|
29
|
-
"@openfn/
|
|
28
|
+
"@openfn/logger": "1.0.5",
|
|
29
|
+
"@openfn/runtime": "1.7.1"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/koa": "^2.13.5",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"tsup": "^6.2.3",
|
|
44
44
|
"typescript": "^4.6.4",
|
|
45
45
|
"yargs": "^17.6.2",
|
|
46
|
-
"@openfn/lightning-mock": "2.2.
|
|
46
|
+
"@openfn/lightning-mock": "2.2.2"
|
|
47
47
|
},
|
|
48
48
|
"files": [
|
|
49
49
|
"dist",
|