@openfn/ws-worker 0.1.8 → 0.2.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,19 @@
1
1
  # ws-worker
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 0e8e20c: BREAKING: Updated exit reasons to `{ reason: "success", error_type, error_message }`
8
+ Add exit reasons to job and attempt complete
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies [a540888]
13
+ - Updated dependencies [0e8e20c]
14
+ - @openfn/runtime@0.1.0
15
+ - @openfn/engine-multi@0.1.6
16
+
3
17
  ## 0.1.8
4
18
 
5
19
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -4,6 +4,20 @@ import { RuntimeEngine } from '@openfn/engine-multi';
4
4
  import { Channel as Channel$1 } from 'phoenix';
5
5
  import { ExecutionPlan } from '@openfn/runtime';
6
6
 
7
+ type ExitReasonStrings =
8
+ | 'success'
9
+ | 'fail'
10
+ | 'crash'
11
+ | 'kill'
12
+ | 'cancel'
13
+ | 'exception';
14
+
15
+ type ExitReason = {
16
+ reason: ExitReasonStrings;
17
+ error_message: string | null;
18
+ error_type: string | null;
19
+ };
20
+
7
21
  type AttemptOptions = {
8
22
  timeout?: number;
9
23
  sanitize?: SanitizePolicies;
@@ -37,6 +51,7 @@ declare type AttemptState = {
37
51
  plan: ExecutionPlan;
38
52
  options: AttemptOptions;
39
53
  dataclips: Record<string, any>;
54
+ reasons: Record<string, ExitReason>;
40
55
  lastDataclipId?: string;
41
56
  };
42
57
  declare type Context = {
package/dist/index.js CHANGED
@@ -210,6 +210,30 @@ var stringify_default = (obj) => stringify(obj, (_key, value) => {
210
210
  return value;
211
211
  });
212
212
 
213
+ // src/api/reasons.ts
214
+ var calculateJobExitReason = (jobId, state, error) => {
215
+ let reason = "success";
216
+ let error_type = null;
217
+ let error_message = null;
218
+ if (error) {
219
+ reason = error.severity ?? "crash";
220
+ error_message = error.message;
221
+ error_type = error.subtype || error.type || error.name;
222
+ } else if (state.errors?.[jobId]) {
223
+ reason = "fail";
224
+ ({ message: error_message, type: error_type } = state.errors[jobId]);
225
+ }
226
+ return { reason, error_type, error_message };
227
+ };
228
+ var calculateAttemptExitReason = (state) => {
229
+ if (state.reasons) {
230
+ const fail = Object.values(state.reasons).find(
231
+ ({ reason }) => reason === "fail"
232
+ );
233
+ return fail || { reason: "success", error_type: null, error_message: null };
234
+ }
235
+ };
236
+
213
237
  // src/api/execute.ts
214
238
  var enc = new TextDecoder("utf-8");
215
239
  var eventMap = {
@@ -219,15 +243,17 @@ var eventMap = {
219
243
  "workflow-log": ATTEMPT_LOG,
220
244
  "workflow-complete": ATTEMPT_COMPLETE
221
245
  };
246
+ var createAttemptState = (plan, options = {}) => ({
247
+ plan,
248
+ lastDataclipId: plan.initialState,
249
+ dataclips: {},
250
+ reasons: {},
251
+ options
252
+ });
222
253
  function execute(channel, engine, logger, plan, options = {}, onComplete = (_result) => {
223
254
  }) {
224
255
  logger.info("execute...");
225
- const state = {
226
- plan,
227
- lastDataclipId: plan.initialState,
228
- dataclips: {},
229
- options
230
- };
256
+ const state = createAttemptState(plan, options);
231
257
  const context = { channel, state, logger, onComplete };
232
258
  const addEvent = (eventName, handler) => {
233
259
  const wrappedFn = async (event) => {
@@ -251,6 +277,7 @@ function execute(channel, engine, logger, plan, options = {}, onComplete = (_res
251
277
  addEvent("workflow-start", onWorkflowStart),
252
278
  addEvent("job-start", onJobStart),
253
279
  addEvent("job-complete", onJobComplete),
280
+ addEvent("job-error", onJobError),
254
281
  addEvent("workflow-log", onJobLog),
255
282
  addEvent("workflow-complete", onWorkflowComplete),
256
283
  addEvent("workflow-error", onWorkflowError)
@@ -288,7 +315,15 @@ function onJobStart({ channel, state }, event) {
288
315
  input_dataclip_id: state.lastDataclipId
289
316
  });
290
317
  }
291
- function onJobComplete({ channel, state }, event) {
318
+ function onJobError(context, event) {
319
+ const { state, error, jobId } = event;
320
+ if (state.errors?.[jobId]?.message === error.message) {
321
+ onJobComplete(context, event);
322
+ } else {
323
+ onJobComplete(context, event, event.error);
324
+ }
325
+ }
326
+ function onJobComplete({ channel, state }, event, error) {
292
327
  const dataclipId = crypto2.randomUUID();
293
328
  const run_id = state.activeRun;
294
329
  const job_id = state.activeJob;
@@ -299,12 +334,20 @@ function onJobComplete({ channel, state }, event) {
299
334
  state.lastDataclipId = dataclipId;
300
335
  delete state.activeRun;
301
336
  delete state.activeJob;
337
+ const { reason, error_message, error_type } = calculateJobExitReason(
338
+ job_id,
339
+ event.state,
340
+ error
341
+ );
342
+ state.reasons[job_id] = { reason, error_message, error_type };
302
343
  return sendEvent(channel, RUN_COMPLETE, {
303
344
  run_id,
304
345
  job_id,
305
346
  output_dataclip_id: dataclipId,
306
347
  output_dataclip: stringify_default(event.state),
307
- reason: "success"
348
+ reason,
349
+ error_message,
350
+ error_type
308
351
  });
309
352
  }
310
353
  function onWorkflowStart({ channel }, _event) {
@@ -312,20 +355,20 @@ function onWorkflowStart({ channel }, _event) {
312
355
  }
313
356
  async function onWorkflowComplete({ state, channel, onComplete }, _event) {
314
357
  const result = state.dataclips[state.lastDataclipId];
358
+ const reason = calculateAttemptExitReason(state);
315
359
  await sendEvent(channel, ATTEMPT_COMPLETE, {
316
360
  final_dataclip_id: state.lastDataclipId,
317
- status: "success",
318
- reason: "ok"
361
+ ...reason
319
362
  });
320
- onComplete(result);
363
+ onComplete({ reason, state: result });
321
364
  }
322
365
  async function onWorkflowError({ state, channel, onComplete }, event) {
366
+ const reason = calculateJobExitReason("", { data: {} }, event);
323
367
  await sendEvent(channel, ATTEMPT_COMPLETE, {
324
- reason: "fail",
325
368
  final_dataclip_id: state.lastDataclipId,
326
- message: event.message
369
+ ...reason
327
370
  });
328
- onComplete({});
371
+ onComplete({ reason });
329
372
  }
330
373
  function onJobLog({ channel, state }, event) {
331
374
  const timeInMicroseconds = BigInt(event.time) / BigInt(1e3);
package/dist/start.js CHANGED
@@ -5192,6 +5192,30 @@ var stringify_default = (obj) => stringify(obj, (_key, value) => {
5192
5192
  return value;
5193
5193
  });
5194
5194
 
5195
+ // src/api/reasons.ts
5196
+ var calculateJobExitReason = (jobId, state, error) => {
5197
+ let reason = "success";
5198
+ let error_type = null;
5199
+ let error_message = null;
5200
+ if (error) {
5201
+ reason = error.severity ?? "crash";
5202
+ error_message = error.message;
5203
+ error_type = error.subtype || error.type || error.name;
5204
+ } else if (state.errors?.[jobId]) {
5205
+ reason = "fail";
5206
+ ({ message: error_message, type: error_type } = state.errors[jobId]);
5207
+ }
5208
+ return { reason, error_type, error_message };
5209
+ };
5210
+ var calculateAttemptExitReason = (state) => {
5211
+ if (state.reasons) {
5212
+ const fail = Object.values(state.reasons).find(
5213
+ ({ reason }) => reason === "fail"
5214
+ );
5215
+ return fail || { reason: "success", error_type: null, error_message: null };
5216
+ }
5217
+ };
5218
+
5195
5219
  // src/api/execute.ts
5196
5220
  var enc = new TextDecoder("utf-8");
5197
5221
  var eventMap = {
@@ -5201,15 +5225,17 @@ var eventMap = {
5201
5225
  "workflow-log": ATTEMPT_LOG,
5202
5226
  "workflow-complete": ATTEMPT_COMPLETE
5203
5227
  };
5228
+ var createAttemptState = (plan, options = {}) => ({
5229
+ plan,
5230
+ lastDataclipId: plan.initialState,
5231
+ dataclips: {},
5232
+ reasons: {},
5233
+ options
5234
+ });
5204
5235
  function execute(channel, engine, logger2, plan, options = {}, onComplete = (_result) => {
5205
5236
  }) {
5206
5237
  logger2.info("execute...");
5207
- const state = {
5208
- plan,
5209
- lastDataclipId: plan.initialState,
5210
- dataclips: {},
5211
- options
5212
- };
5238
+ const state = createAttemptState(plan, options);
5213
5239
  const context = { channel, state, logger: logger2, onComplete };
5214
5240
  const addEvent = (eventName, handler) => {
5215
5241
  const wrappedFn = async (event) => {
@@ -5233,6 +5259,7 @@ function execute(channel, engine, logger2, plan, options = {}, onComplete = (_re
5233
5259
  addEvent("workflow-start", onWorkflowStart),
5234
5260
  addEvent("job-start", onJobStart),
5235
5261
  addEvent("job-complete", onJobComplete),
5262
+ addEvent("job-error", onJobError),
5236
5263
  addEvent("workflow-log", onJobLog),
5237
5264
  addEvent("workflow-complete", onWorkflowComplete),
5238
5265
  addEvent("workflow-error", onWorkflowError)
@@ -5270,7 +5297,15 @@ function onJobStart({ channel, state }, event) {
5270
5297
  input_dataclip_id: state.lastDataclipId
5271
5298
  });
5272
5299
  }
5273
- function onJobComplete({ channel, state }, event) {
5300
+ function onJobError(context, event) {
5301
+ const { state, error, jobId } = event;
5302
+ if (state.errors?.[jobId]?.message === error.message) {
5303
+ onJobComplete(context, event);
5304
+ } else {
5305
+ onJobComplete(context, event, event.error);
5306
+ }
5307
+ }
5308
+ function onJobComplete({ channel, state }, event, error) {
5274
5309
  const dataclipId = crypto3.randomUUID();
5275
5310
  const run_id = state.activeRun;
5276
5311
  const job_id = state.activeJob;
@@ -5281,12 +5316,20 @@ function onJobComplete({ channel, state }, event) {
5281
5316
  state.lastDataclipId = dataclipId;
5282
5317
  delete state.activeRun;
5283
5318
  delete state.activeJob;
5319
+ const { reason, error_message, error_type } = calculateJobExitReason(
5320
+ job_id,
5321
+ event.state,
5322
+ error
5323
+ );
5324
+ state.reasons[job_id] = { reason, error_message, error_type };
5284
5325
  return sendEvent(channel, RUN_COMPLETE, {
5285
5326
  run_id,
5286
5327
  job_id,
5287
5328
  output_dataclip_id: dataclipId,
5288
5329
  output_dataclip: stringify_default(event.state),
5289
- reason: "success"
5330
+ reason,
5331
+ error_message,
5332
+ error_type
5290
5333
  });
5291
5334
  }
5292
5335
  function onWorkflowStart({ channel }, _event) {
@@ -5294,20 +5337,20 @@ function onWorkflowStart({ channel }, _event) {
5294
5337
  }
5295
5338
  async function onWorkflowComplete({ state, channel, onComplete }, _event) {
5296
5339
  const result = state.dataclips[state.lastDataclipId];
5340
+ const reason = calculateAttemptExitReason(state);
5297
5341
  await sendEvent(channel, ATTEMPT_COMPLETE, {
5298
5342
  final_dataclip_id: state.lastDataclipId,
5299
- status: "success",
5300
- reason: "ok"
5343
+ ...reason
5301
5344
  });
5302
- onComplete(result);
5345
+ onComplete({ reason, state: result });
5303
5346
  }
5304
5347
  async function onWorkflowError({ state, channel, onComplete }, event) {
5348
+ const reason = calculateJobExitReason("", { data: {} }, event);
5305
5349
  await sendEvent(channel, ATTEMPT_COMPLETE, {
5306
- reason: "fail",
5307
5350
  final_dataclip_id: state.lastDataclipId,
5308
- message: event.message
5351
+ ...reason
5309
5352
  });
5310
- onComplete({});
5353
+ onComplete({ reason });
5311
5354
  }
5312
5355
  function onJobLog({ channel, state }, event) {
5313
5356
  const timeInMicroseconds = BigInt(event.time) / BigInt(1e3);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfn/ws-worker",
3
- "version": "0.1.8",
3
+ "version": "0.2.0",
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.5",
24
+ "@openfn/engine-multi": "0.1.6",
25
25
  "@openfn/logger": "0.0.19",
26
- "@openfn/runtime": "0.0.33"
26
+ "@openfn/runtime": "0.1.0"
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.6"
43
+ "@openfn/lightning-mock": "1.0.7"
44
44
  },
45
45
  "files": [
46
46
  "dist",