@openfn/ws-worker 0.2.4 → 0.2.6
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.d.ts +16 -10
- package/dist/index.js +65 -31
- package/dist/start.js +72 -32
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# ws-worker
|
|
2
2
|
|
|
3
|
+
## 0.2.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 0fb2d58: correctly handle input_dataclip_id for runs
|
|
8
|
+
- Updated dependencies [c8e9d51]
|
|
9
|
+
- Updated dependencies [7f352d2]
|
|
10
|
+
- @openfn/engine-multi@0.1.10
|
|
11
|
+
- @openfn/runtime@0.1.3
|
|
12
|
+
|
|
13
|
+
## 0.2.5
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 36337d7: When calculating exit reasons, exclude non-executed downstream nodes in leaf calculation. (i.e., look at the final executed node in each branch when determining the attempt exit reason.)
|
|
18
|
+
|
|
3
19
|
## 0.2.4
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import Koa from 'koa';
|
|
2
2
|
import { SanitizePolicies, Logger } from '@openfn/logger';
|
|
3
3
|
import { Channel as Channel$1 } from 'phoenix';
|
|
4
|
-
import { ExecutionPlan } from '@openfn/runtime';
|
|
5
4
|
import { RuntimeEngine } from '@openfn/engine-multi';
|
|
6
5
|
|
|
7
6
|
type ExitReasonStrings =
|
|
@@ -23,6 +22,22 @@ type AttemptOptions = {
|
|
|
23
22
|
sanitize?: SanitizePolicies;
|
|
24
23
|
};
|
|
25
24
|
|
|
25
|
+
// Internal server state for each attempt
|
|
26
|
+
type AttemptState = {
|
|
27
|
+
activeRun?: string;
|
|
28
|
+
activeJob?: string;
|
|
29
|
+
plan: ExecutionPlan;
|
|
30
|
+
options: AttemptOptions;
|
|
31
|
+
dataclips: Record<string, any>;
|
|
32
|
+
// For each run, map the input ids
|
|
33
|
+
// TODO better name maybe?
|
|
34
|
+
inputDataclips: Record<string, string>;
|
|
35
|
+
reasons: Record<string, ExitReason>;
|
|
36
|
+
|
|
37
|
+
// final dataclip id
|
|
38
|
+
lastDataclipId?: string;
|
|
39
|
+
};
|
|
40
|
+
|
|
26
41
|
type ReceiveHook = {
|
|
27
42
|
receive: (
|
|
28
43
|
status: 'ok' | 'timeout' | 'error',
|
|
@@ -45,15 +60,6 @@ interface Channel extends Channel$1 {
|
|
|
45
60
|
// join: () => ReceiveHook;
|
|
46
61
|
}
|
|
47
62
|
|
|
48
|
-
declare type AttemptState = {
|
|
49
|
-
activeRun?: string;
|
|
50
|
-
activeJob?: string;
|
|
51
|
-
plan: ExecutionPlan;
|
|
52
|
-
options: AttemptOptions;
|
|
53
|
-
dataclips: Record<string, any>;
|
|
54
|
-
reasons: Record<string, ExitReason>;
|
|
55
|
-
lastDataclipId?: string;
|
|
56
|
-
};
|
|
57
63
|
declare type Context = {
|
|
58
64
|
channel: Channel;
|
|
59
65
|
state: AttemptState;
|
package/dist/index.js
CHANGED
|
@@ -215,6 +215,35 @@ var stringify_default = (obj) => stringify(obj, (_key, value) => {
|
|
|
215
215
|
return value;
|
|
216
216
|
});
|
|
217
217
|
|
|
218
|
+
// src/util/create-attempt-state.ts
|
|
219
|
+
var create_attempt_state_default = (plan, options = {}) => {
|
|
220
|
+
const state = {
|
|
221
|
+
plan,
|
|
222
|
+
lastDataclipId: "",
|
|
223
|
+
dataclips: {},
|
|
224
|
+
inputDataclips: {},
|
|
225
|
+
reasons: {},
|
|
226
|
+
options
|
|
227
|
+
};
|
|
228
|
+
if (typeof plan.initialState === "string") {
|
|
229
|
+
let startNode = plan.jobs[0];
|
|
230
|
+
if (plan.start) {
|
|
231
|
+
startNode = plan.jobs.find(({ id }) => id === plan.start);
|
|
232
|
+
}
|
|
233
|
+
const initialRuns = [];
|
|
234
|
+
if (!startNode.expression) {
|
|
235
|
+
initialRuns.push(...Object.keys(startNode.next));
|
|
236
|
+
} else {
|
|
237
|
+
initialRuns.push(startNode.id);
|
|
238
|
+
}
|
|
239
|
+
initialRuns.forEach((id) => {
|
|
240
|
+
state.inputDataclips[id] = plan.initialState;
|
|
241
|
+
});
|
|
242
|
+
} else {
|
|
243
|
+
}
|
|
244
|
+
return state;
|
|
245
|
+
};
|
|
246
|
+
|
|
218
247
|
// src/api/reasons.ts
|
|
219
248
|
var calculateJobExitReason = (jobId, state = { data: {} }, error) => {
|
|
220
249
|
let reason = "success";
|
|
@@ -230,9 +259,16 @@ var calculateJobExitReason = (jobId, state = { data: {} }, error) => {
|
|
|
230
259
|
}
|
|
231
260
|
return { reason, error_type, error_message };
|
|
232
261
|
};
|
|
262
|
+
var isLeafNode = (state, job) => {
|
|
263
|
+
if (!job.next || Object.keys(job.next).length == 0) {
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
const hasDownstream = Object.keys(job.next).find((id) => state.reasons[id]);
|
|
267
|
+
return !hasDownstream;
|
|
268
|
+
};
|
|
233
269
|
var calculateAttemptExitReason = (state) => {
|
|
234
270
|
if (state.plan && state.reasons) {
|
|
235
|
-
const leafJobReasons = state.plan.jobs.filter((
|
|
271
|
+
const leafJobReasons = state.plan.jobs.filter((job) => isLeafNode(state, job)).map(({ id }) => state.reasons[id]);
|
|
236
272
|
const fail = leafJobReasons.find((r) => r && r.reason === "fail");
|
|
237
273
|
if (fail) {
|
|
238
274
|
return fail;
|
|
@@ -250,17 +286,10 @@ var eventMap = {
|
|
|
250
286
|
"workflow-log": ATTEMPT_LOG,
|
|
251
287
|
"workflow-complete": ATTEMPT_COMPLETE
|
|
252
288
|
};
|
|
253
|
-
var createAttemptState = (plan, options = {}) => ({
|
|
254
|
-
plan,
|
|
255
|
-
lastDataclipId: plan.initialState,
|
|
256
|
-
dataclips: {},
|
|
257
|
-
reasons: {},
|
|
258
|
-
options
|
|
259
|
-
});
|
|
260
289
|
function execute(channel, engine, logger, plan, options = {}, onComplete = (_result) => {
|
|
261
290
|
}) {
|
|
262
|
-
logger.info("
|
|
263
|
-
const state =
|
|
291
|
+
logger.info("executing ", plan.id);
|
|
292
|
+
const state = create_attempt_state_default(plan, options);
|
|
264
293
|
const context = { channel, state, logger, onComplete };
|
|
265
294
|
const addEvent = (eventName, handler) => {
|
|
266
295
|
const wrappedFn = async (event) => {
|
|
@@ -305,7 +334,11 @@ function execute(channel, engine, logger, plan, options = {}, onComplete = (_res
|
|
|
305
334
|
try {
|
|
306
335
|
engine.execute(plan, { resolvers, ...options });
|
|
307
336
|
} catch (e) {
|
|
308
|
-
onWorkflowError(context, {
|
|
337
|
+
onWorkflowError(context, {
|
|
338
|
+
workflowId: plan.id,
|
|
339
|
+
message: e.message,
|
|
340
|
+
type: e.type
|
|
341
|
+
});
|
|
309
342
|
}
|
|
310
343
|
});
|
|
311
344
|
return context;
|
|
@@ -316,10 +349,11 @@ var sendEvent = (channel, event, payload) => new Promise((resolve, reject) => {
|
|
|
316
349
|
function onJobStart({ channel, state }, event) {
|
|
317
350
|
state.activeRun = crypto2.randomUUID();
|
|
318
351
|
state.activeJob = event.jobId;
|
|
352
|
+
const input_dataclip_id = state.inputDataclips[event.jobId];
|
|
319
353
|
return sendEvent(channel, RUN_START, {
|
|
320
354
|
run_id: state.activeRun,
|
|
321
355
|
job_id: state.activeJob,
|
|
322
|
-
input_dataclip_id
|
|
356
|
+
input_dataclip_id
|
|
323
357
|
});
|
|
324
358
|
}
|
|
325
359
|
function onJobError(context, event) {
|
|
@@ -339,27 +373,27 @@ function onJobComplete({ channel, state }, event, error) {
|
|
|
339
373
|
}
|
|
340
374
|
state.dataclips[dataclipId] = event.state;
|
|
341
375
|
state.lastDataclipId = dataclipId;
|
|
376
|
+
event.next?.forEach((nextJobId) => {
|
|
377
|
+
state.inputDataclips[nextJobId] = dataclipId;
|
|
378
|
+
});
|
|
342
379
|
delete state.activeRun;
|
|
343
380
|
delete state.activeJob;
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
} catch (e) {
|
|
361
|
-
console.log(e);
|
|
362
|
-
}
|
|
381
|
+
const { reason, error_message, error_type } = calculateJobExitReason(
|
|
382
|
+
job_id,
|
|
383
|
+
event.state,
|
|
384
|
+
error
|
|
385
|
+
);
|
|
386
|
+
state.reasons[job_id] = { reason, error_message, error_type };
|
|
387
|
+
const evt = {
|
|
388
|
+
run_id,
|
|
389
|
+
job_id,
|
|
390
|
+
output_dataclip_id: dataclipId,
|
|
391
|
+
output_dataclip: stringify_default(event.state),
|
|
392
|
+
reason,
|
|
393
|
+
error_message,
|
|
394
|
+
error_type
|
|
395
|
+
};
|
|
396
|
+
return sendEvent(channel, RUN_COMPLETE, evt);
|
|
363
397
|
}
|
|
364
398
|
function onWorkflowStart({ channel }, _event) {
|
|
365
399
|
return sendEvent(channel, ATTEMPT_START);
|
package/dist/start.js
CHANGED
|
@@ -4939,7 +4939,13 @@ async function createMock() {
|
|
|
4939
4939
|
nextState = initialState;
|
|
4940
4940
|
}
|
|
4941
4941
|
}
|
|
4942
|
-
dispatch("job-complete", {
|
|
4942
|
+
dispatch("job-complete", {
|
|
4943
|
+
workflowId,
|
|
4944
|
+
jobId,
|
|
4945
|
+
state: nextState,
|
|
4946
|
+
runId,
|
|
4947
|
+
next: []
|
|
4948
|
+
});
|
|
4943
4949
|
return nextState;
|
|
4944
4950
|
};
|
|
4945
4951
|
const execute2 = (xplan, options = {
|
|
@@ -5197,6 +5203,35 @@ var stringify_default = (obj) => stringify(obj, (_key, value) => {
|
|
|
5197
5203
|
return value;
|
|
5198
5204
|
});
|
|
5199
5205
|
|
|
5206
|
+
// src/util/create-attempt-state.ts
|
|
5207
|
+
var create_attempt_state_default = (plan, options = {}) => {
|
|
5208
|
+
const state = {
|
|
5209
|
+
plan,
|
|
5210
|
+
lastDataclipId: "",
|
|
5211
|
+
dataclips: {},
|
|
5212
|
+
inputDataclips: {},
|
|
5213
|
+
reasons: {},
|
|
5214
|
+
options
|
|
5215
|
+
};
|
|
5216
|
+
if (typeof plan.initialState === "string") {
|
|
5217
|
+
let startNode = plan.jobs[0];
|
|
5218
|
+
if (plan.start) {
|
|
5219
|
+
startNode = plan.jobs.find(({ id }) => id === plan.start);
|
|
5220
|
+
}
|
|
5221
|
+
const initialRuns = [];
|
|
5222
|
+
if (!startNode.expression) {
|
|
5223
|
+
initialRuns.push(...Object.keys(startNode.next));
|
|
5224
|
+
} else {
|
|
5225
|
+
initialRuns.push(startNode.id);
|
|
5226
|
+
}
|
|
5227
|
+
initialRuns.forEach((id) => {
|
|
5228
|
+
state.inputDataclips[id] = plan.initialState;
|
|
5229
|
+
});
|
|
5230
|
+
} else {
|
|
5231
|
+
}
|
|
5232
|
+
return state;
|
|
5233
|
+
};
|
|
5234
|
+
|
|
5200
5235
|
// src/api/reasons.ts
|
|
5201
5236
|
var calculateJobExitReason = (jobId, state = { data: {} }, error) => {
|
|
5202
5237
|
let reason = "success";
|
|
@@ -5212,9 +5247,16 @@ var calculateJobExitReason = (jobId, state = { data: {} }, error) => {
|
|
|
5212
5247
|
}
|
|
5213
5248
|
return { reason, error_type, error_message };
|
|
5214
5249
|
};
|
|
5250
|
+
var isLeafNode = (state, job) => {
|
|
5251
|
+
if (!job.next || Object.keys(job.next).length == 0) {
|
|
5252
|
+
return true;
|
|
5253
|
+
}
|
|
5254
|
+
const hasDownstream = Object.keys(job.next).find((id) => state.reasons[id]);
|
|
5255
|
+
return !hasDownstream;
|
|
5256
|
+
};
|
|
5215
5257
|
var calculateAttemptExitReason = (state) => {
|
|
5216
5258
|
if (state.plan && state.reasons) {
|
|
5217
|
-
const leafJobReasons = state.plan.jobs.filter((
|
|
5259
|
+
const leafJobReasons = state.plan.jobs.filter((job) => isLeafNode(state, job)).map(({ id }) => state.reasons[id]);
|
|
5218
5260
|
const fail = leafJobReasons.find((r) => r && r.reason === "fail");
|
|
5219
5261
|
if (fail) {
|
|
5220
5262
|
return fail;
|
|
@@ -5232,17 +5274,10 @@ var eventMap = {
|
|
|
5232
5274
|
"workflow-log": ATTEMPT_LOG,
|
|
5233
5275
|
"workflow-complete": ATTEMPT_COMPLETE
|
|
5234
5276
|
};
|
|
5235
|
-
var createAttemptState = (plan, options = {}) => ({
|
|
5236
|
-
plan,
|
|
5237
|
-
lastDataclipId: plan.initialState,
|
|
5238
|
-
dataclips: {},
|
|
5239
|
-
reasons: {},
|
|
5240
|
-
options
|
|
5241
|
-
});
|
|
5242
5277
|
function execute(channel, engine, logger2, plan, options = {}, onComplete = (_result) => {
|
|
5243
5278
|
}) {
|
|
5244
|
-
logger2.info("
|
|
5245
|
-
const state =
|
|
5279
|
+
logger2.info("executing ", plan.id);
|
|
5280
|
+
const state = create_attempt_state_default(plan, options);
|
|
5246
5281
|
const context = { channel, state, logger: logger2, onComplete };
|
|
5247
5282
|
const addEvent = (eventName, handler) => {
|
|
5248
5283
|
const wrappedFn = async (event) => {
|
|
@@ -5287,7 +5322,11 @@ function execute(channel, engine, logger2, plan, options = {}, onComplete = (_re
|
|
|
5287
5322
|
try {
|
|
5288
5323
|
engine.execute(plan, { resolvers, ...options });
|
|
5289
5324
|
} catch (e) {
|
|
5290
|
-
onWorkflowError(context, {
|
|
5325
|
+
onWorkflowError(context, {
|
|
5326
|
+
workflowId: plan.id,
|
|
5327
|
+
message: e.message,
|
|
5328
|
+
type: e.type
|
|
5329
|
+
});
|
|
5291
5330
|
}
|
|
5292
5331
|
});
|
|
5293
5332
|
return context;
|
|
@@ -5298,10 +5337,11 @@ var sendEvent = (channel, event, payload) => new Promise((resolve5, reject) => {
|
|
|
5298
5337
|
function onJobStart({ channel, state }, event) {
|
|
5299
5338
|
state.activeRun = crypto3.randomUUID();
|
|
5300
5339
|
state.activeJob = event.jobId;
|
|
5340
|
+
const input_dataclip_id = state.inputDataclips[event.jobId];
|
|
5301
5341
|
return sendEvent(channel, RUN_START, {
|
|
5302
5342
|
run_id: state.activeRun,
|
|
5303
5343
|
job_id: state.activeJob,
|
|
5304
|
-
input_dataclip_id
|
|
5344
|
+
input_dataclip_id
|
|
5305
5345
|
});
|
|
5306
5346
|
}
|
|
5307
5347
|
function onJobError(context, event) {
|
|
@@ -5321,27 +5361,27 @@ function onJobComplete({ channel, state }, event, error) {
|
|
|
5321
5361
|
}
|
|
5322
5362
|
state.dataclips[dataclipId] = event.state;
|
|
5323
5363
|
state.lastDataclipId = dataclipId;
|
|
5364
|
+
event.next?.forEach((nextJobId) => {
|
|
5365
|
+
state.inputDataclips[nextJobId] = dataclipId;
|
|
5366
|
+
});
|
|
5324
5367
|
delete state.activeRun;
|
|
5325
5368
|
delete state.activeJob;
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
} catch (e) {
|
|
5343
|
-
console.log(e);
|
|
5344
|
-
}
|
|
5369
|
+
const { reason, error_message, error_type } = calculateJobExitReason(
|
|
5370
|
+
job_id,
|
|
5371
|
+
event.state,
|
|
5372
|
+
error
|
|
5373
|
+
);
|
|
5374
|
+
state.reasons[job_id] = { reason, error_message, error_type };
|
|
5375
|
+
const evt = {
|
|
5376
|
+
run_id,
|
|
5377
|
+
job_id,
|
|
5378
|
+
output_dataclip_id: dataclipId,
|
|
5379
|
+
output_dataclip: stringify_default(event.state),
|
|
5380
|
+
reason,
|
|
5381
|
+
error_message,
|
|
5382
|
+
error_type
|
|
5383
|
+
};
|
|
5384
|
+
return sendEvent(channel, RUN_COMPLETE, evt);
|
|
5345
5385
|
}
|
|
5346
5386
|
function onWorkflowStart({ channel }, _event) {
|
|
5347
5387
|
return sendEvent(channel, ATTEMPT_START);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfn/ws-worker",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "A Websocket Worker to connect Lightning to a Runtime Engine",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"koa-logger": "^3.2.1",
|
|
22
22
|
"phoenix": "^1.7.7",
|
|
23
23
|
"ws": "^8.14.1",
|
|
24
|
-
"@openfn/engine-multi": "0.1.
|
|
24
|
+
"@openfn/engine-multi": "0.1.10",
|
|
25
25
|
"@openfn/logger": "0.0.19",
|
|
26
|
-
"@openfn/runtime": "0.1.
|
|
26
|
+
"@openfn/runtime": "0.1.3"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/koa": "^2.13.5",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"tsup": "^6.2.3",
|
|
41
41
|
"typescript": "^4.6.4",
|
|
42
42
|
"yargs": "^17.6.2",
|
|
43
|
-
"@openfn/lightning-mock": "1.0.
|
|
43
|
+
"@openfn/lightning-mock": "1.0.11"
|
|
44
44
|
},
|
|
45
45
|
"files": [
|
|
46
46
|
"dist",
|