@hotmeshio/hotmesh 0.0.43 → 0.0.44

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.
Files changed (46) hide show
  1. package/build/package.json +1 -1
  2. package/build/services/activities/trigger.js +7 -1
  3. package/build/services/durable/exporter.d.ts +105 -0
  4. package/build/services/durable/exporter.js +374 -0
  5. package/build/services/durable/factory.js +6 -63
  6. package/build/services/durable/handle.d.ts +4 -0
  7. package/build/services/durable/handle.js +5 -0
  8. package/build/services/durable/workflow.js +24 -21
  9. package/build/services/engine/index.d.ts +6 -1
  10. package/build/services/engine/index.js +9 -2
  11. package/build/services/exporter/index.d.ts +46 -0
  12. package/build/services/exporter/index.js +126 -0
  13. package/build/services/hotmesh/index.d.ts +4 -1
  14. package/build/services/hotmesh/index.js +6 -0
  15. package/build/services/quorum/index.js +2 -1
  16. package/build/services/router/index.d.ts +3 -0
  17. package/build/services/router/index.js +3 -0
  18. package/build/services/store/index.d.ts +5 -2
  19. package/build/services/store/index.js +54 -6
  20. package/build/services/task/index.js +5 -1
  21. package/build/services/worker/index.js +5 -4
  22. package/build/types/activity.d.ts +6 -1
  23. package/build/types/exporter.d.ts +51 -0
  24. package/build/types/exporter.js +8 -0
  25. package/build/types/index.d.ts +1 -0
  26. package/build/types/quorum.d.ts +1 -0
  27. package/build/types/task.d.ts +1 -1
  28. package/package.json +1 -1
  29. package/services/activities/trigger.ts +14 -0
  30. package/services/durable/exporter.ts +408 -0
  31. package/services/durable/factory.ts +6 -63
  32. package/services/durable/handle.ts +12 -0
  33. package/services/durable/workflow.ts +24 -22
  34. package/services/engine/index.ts +20 -5
  35. package/services/exporter/index.ts +147 -0
  36. package/services/hotmesh/index.ts +8 -1
  37. package/services/quorum/index.ts +2 -1
  38. package/services/router/index.ts +3 -0
  39. package/services/store/index.ts +56 -7
  40. package/services/task/index.ts +4 -1
  41. package/services/worker/index.ts +6 -5
  42. package/types/activity.ts +6 -1
  43. package/types/exporter.ts +61 -0
  44. package/types/index.ts +13 -1
  45. package/types/quorum.ts +1 -0
  46. package/types/task.ts +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/hotmesh",
3
- "version": "0.0.43",
3
+ "version": "0.0.44",
4
4
  "description": "Unbreakable Workflows",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -158,11 +158,17 @@ class Trigger extends activity_1.Activity {
158
158
  async registerJobDependency(multi) {
159
159
  const depKey = this.config.stats?.parent ?? this.context.metadata.pj;
160
160
  let resolvedDepKey = depKey ? pipe_1.Pipe.resolve(depKey, this.context) : '';
161
+ const adjKey = this.config.stats?.adjacent;
162
+ let resolvedAdjKey = depKey ? pipe_1.Pipe.resolve(adjKey, this.context) : '';
161
163
  if (!resolvedDepKey) {
162
164
  resolvedDepKey = this.context.metadata.pj;
163
165
  }
164
166
  if (resolvedDepKey) {
165
- await this.store.registerJobDependency(resolvedDepKey, this.context.metadata.tpc, this.context.metadata.jid, this.context.metadata.gid, multi);
167
+ const isParentOrigin = (resolvedDepKey === this.context.metadata.pj) || (resolvedDepKey === resolvedAdjKey);
168
+ await this.store.registerJobDependency(isParentOrigin ? 'expire-child' : 'expire', resolvedDepKey, this.context.metadata.tpc, this.context.metadata.jid, this.context.metadata.gid, multi);
169
+ }
170
+ if (resolvedAdjKey && resolvedAdjKey !== resolvedDepKey) {
171
+ await this.store.registerJobDependency('child', resolvedAdjKey, this.context.metadata.tpc, this.context.metadata.jid, this.context.metadata.gid, multi);
166
172
  }
167
173
  }
168
174
  async setStats(multi) {
@@ -0,0 +1,105 @@
1
+ import { ILogger } from '../logger';
2
+ import { StoreService } from '../store';
3
+ import { StringStringType, Symbols } from "../../types";
4
+ import { RedisClient, RedisMulti } from '../../types/redis';
5
+ import { ActivityAction, DependencyExport, ExportItem, ExportOptions, JobAction, JobActionExport, DurableJobExport, JobTimeline } from '../../types/exporter';
6
+ import { SerializerService } from '../serializer';
7
+ /**
8
+ * Downloads job data from Redis (hscan, hmget, hgetall)
9
+ * Splits, Inflates, and Sorts the job data for use in durable contexts
10
+ */
11
+ declare class ExporterService {
12
+ appId: string;
13
+ logger: ILogger;
14
+ serializer: SerializerService;
15
+ store: StoreService<RedisClient, RedisMulti>;
16
+ symbols: Promise<Symbols> | Symbols;
17
+ /**
18
+ * Friendly names for the activity ids
19
+ */
20
+ activitySymbols: Symbols;
21
+ transitions: {
22
+ trigger: string[];
23
+ pivot: string[];
24
+ worker: string[];
25
+ sleeper: string[];
26
+ awaiter: string[];
27
+ retryer: string[];
28
+ hook: string[];
29
+ hook_pivot: string[];
30
+ hook_worker: string[];
31
+ hook_sleeper: string[];
32
+ hook_awaiter: string[];
33
+ hook_retryer: string[];
34
+ };
35
+ cycles: {
36
+ sleep_cycler: string[];
37
+ await_cycler: string[];
38
+ retry_cycler: string[];
39
+ hook_sleep_cycler: string[];
40
+ hook_await_cycler: string[];
41
+ hook_retry_cycler: string[];
42
+ };
43
+ constructor(appId: string, store: StoreService<RedisClient, RedisMulti>, logger: ILogger);
44
+ /**
45
+ * Convert the job hash and dependency list into a DurableJobExport object.
46
+ * This object contains various facets that describe the interaction
47
+ * in terms relevant to narrative storytelling.
48
+ */
49
+ export(jobId: string, options?: ExportOptions): Promise<DurableJobExport>;
50
+ /**
51
+ * Interleave actions into the replay timeline to create
52
+ * a time-ordered timeline of the entire interaction, beginning
53
+ * with the entry trigger and concluding with the scrubber
54
+ * activity. Using the returned timeline, it is possible to
55
+ * create an animated narrative of the job, highlighting
56
+ * activities in the graph according to the timeline's
57
+ * activity-created (/ac) and activity-updated (/au) entries.
58
+ */
59
+ createTimeline(replay: ExportItem[], actions: JobActionExport): JobTimeline[];
60
+ /**
61
+ * Interleave actions into the 'worker' and 'hook_worker'
62
+ * activities (between their /ac and /au entries)
63
+ */
64
+ interleaveActions(target: JobAction, actions: ActivityAction[]): void;
65
+ isPausingAction(actionType: string): boolean;
66
+ isMainEntry(key: string): boolean;
67
+ isHookEntry(key: string): boolean;
68
+ /**
69
+ * Inflates the key from Redis, 3-character symbol
70
+ * into a human-readable JSON path, reflecting the
71
+ * tree-like structure of the unidimensional Hash
72
+ */
73
+ inflateKey(key: string): string;
74
+ /**
75
+ * Inflates the dependency data from Redis into a DurableJobExport object by
76
+ * organizing the dimensional isolate in sch a way asto interleave
77
+ * into a story
78
+ * @param data - the dependency data from Redis
79
+ * @returns - the organized dependency data
80
+ */
81
+ inflateDependencyData(data: string[], actions: JobActionExport): DependencyExport[];
82
+ /**
83
+ * Adds historical actions (proxyActivity, executeChild)
84
+ * using the `dependency list` to determine
85
+ * after-the-fact what happened within the 'black-box'
86
+ * worker function. This is necessary to interleave the
87
+ * actions into the replay timeline, given that it isn't
88
+ * really possible to know the inner-workings of the user's
89
+ * function
90
+ *
91
+ */
92
+ seedActions(type: 'flow' | 'hook' | 'other', action: string, topic: string, dep: string, prefix: string, dimensionKey: string, actions: JobActionExport, jobId: string): void;
93
+ /**
94
+ * Inflates the job data from Redis into a DurableJobExport object
95
+ * @param jobHash - the job data from Redis
96
+ * @param dependencyList - the list of dependencies for the job
97
+ * @returns - the inflated job data
98
+ */
99
+ inflate(jobHash: StringStringType, dependencyList: string[]): DurableJobExport;
100
+ inflateProcess(match: RegExpMatchArray, value: string, replay: ExportItem[]): void;
101
+ inflateActions(key: string, value: string, actions: JobActionExport): void;
102
+ reverseSort(aKey: ExportItem, bKey: ExportItem): 1 | -1 | 0;
103
+ dateSort(aKey: ExportItem, bKey: ExportItem): 1 | -1 | 0;
104
+ }
105
+ export { ExporterService };
@@ -0,0 +1,374 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ExporterService = void 0;
4
+ const serializer_1 = require("../serializer");
5
+ const utils_1 = require("../../modules/utils");
6
+ /**
7
+ * Downloads job data from Redis (hscan, hmget, hgetall)
8
+ * Splits, Inflates, and Sorts the job data for use in durable contexts
9
+ */
10
+ class ExporterService {
11
+ constructor(appId, store, logger) {
12
+ /**
13
+ * Friendly names for the activity ids
14
+ */
15
+ this.activitySymbols = {
16
+ t1: 'trigger',
17
+ a1: 'pivot',
18
+ w1: 'worker',
19
+ a592: 'sleeper',
20
+ a594: 'awaiter',
21
+ a599: 'retryer',
22
+ c592: 'sleep_cycler',
23
+ c594: 'await_cycler',
24
+ c599: 'retry_cycler',
25
+ s5: 'scrubber',
26
+ sig: 'hook',
27
+ siga1: 'hook_pivot',
28
+ sigw1: 'hook_worker',
29
+ siga592: 'hook_sleeper',
30
+ siga594: 'hook_awaiter',
31
+ siga599: 'hook_retryer',
32
+ sigc592: 'hook_sleep_cycler',
33
+ sigc594: 'hook_await_cycler',
34
+ sigc599: 'hook_retry_cycler',
35
+ };
36
+ //adjacent transitions
37
+ this.transitions = {
38
+ trigger: ['pivot', 'hook'],
39
+ pivot: ['worker'],
40
+ worker: ['sleeper', 'awaiter', 'retryer', 'scrubber'],
41
+ sleeper: ['sleep_cycler'],
42
+ awaiter: ['await_cycler'],
43
+ retryer: ['retry_cycler'],
44
+ hook: ['hook_pivot'],
45
+ hook_pivot: ['hook_worker'],
46
+ hook_worker: ['hook_sleeper', 'hook_awaiter', 'hook_retryer'],
47
+ hook_sleeper: ['hook_sleep_cycler'],
48
+ hook_awaiter: ['hook_await_cycler'],
49
+ hook_retryer: ['hook_retry_cycler'],
50
+ };
51
+ //goto transitions
52
+ this.cycles = {
53
+ sleep_cycler: ['pivot'],
54
+ await_cycler: ['pivot'],
55
+ retry_cycler: ['pivot'],
56
+ hook_sleep_cycler: ['hook_pivot'],
57
+ hook_await_cycler: ['hook_pivot'],
58
+ hook_retry_cycler: ['hook_pivot'],
59
+ };
60
+ this.appId = appId;
61
+ this.logger = logger;
62
+ this.store = store;
63
+ this.serializer = new serializer_1.SerializerService();
64
+ }
65
+ /**
66
+ * Convert the job hash and dependency list into a DurableJobExport object.
67
+ * This object contains various facets that describe the interaction
68
+ * in terms relevant to narrative storytelling.
69
+ */
70
+ async export(jobId, options = {}) {
71
+ if (!this.symbols) {
72
+ this.symbols = this.store.getAllSymbols();
73
+ this.symbols = await this.symbols;
74
+ }
75
+ const depData = await this.store.getDependencies(jobId);
76
+ const jobData = await this.store.getRaw(jobId);
77
+ const jobExport = this.inflate(jobData, depData);
78
+ return jobExport;
79
+ }
80
+ /**
81
+ * Interleave actions into the replay timeline to create
82
+ * a time-ordered timeline of the entire interaction, beginning
83
+ * with the entry trigger and concluding with the scrubber
84
+ * activity. Using the returned timeline, it is possible to
85
+ * create an animated narrative of the job, highlighting
86
+ * activities in the graph according to the timeline's
87
+ * activity-created (/ac) and activity-updated (/au) entries.
88
+ */
89
+ createTimeline(replay, actions) {
90
+ const timeline = [];
91
+ replay.forEach((item) => {
92
+ const dimensions = item[0];
93
+ const parts = dimensions.split('/');
94
+ const activityName = item[1].split('/')[0];
95
+ const duplex = item[1].endsWith('/ac') ? 'entry' : 'exit';
96
+ const timestamp = item[2];
97
+ const event = {
98
+ activity: activityName,
99
+ duplex: duplex,
100
+ dimension: dimensions,
101
+ timestamp,
102
+ };
103
+ timeline.push(event);
104
+ if (this.isMainEntry(item[1])) {
105
+ event.actions = [];
106
+ this.interleaveActions(actions.main, event.actions);
107
+ }
108
+ else if (this.isHookEntry(item[1])) {
109
+ const hookDimension = `/${parts[1]}/${parts[2]}`;
110
+ const hookActions = actions.hooks[hookDimension];
111
+ event.actions = [];
112
+ this.interleaveActions(hookActions, event.actions);
113
+ }
114
+ });
115
+ return timeline;
116
+ }
117
+ /**
118
+ * Interleave actions into the 'worker' and 'hook_worker'
119
+ * activities (between their /ac and /au entries)
120
+ */
121
+ interleaveActions(target, actions) {
122
+ if (target) {
123
+ for (let i = target.cursor + 1; i < target.items.length; i++) {
124
+ const [_, actionType, jobOrIndex] = target.items[i];
125
+ actions.push({ action: actionType, target: jobOrIndex });
126
+ target.cursor = i;
127
+ if (this.isPausingAction(actionType)) {
128
+ break;
129
+ }
130
+ }
131
+ }
132
+ }
133
+ isPausingAction(actionType) {
134
+ return actionType === 'sleep' || actionType === 'waitForSignal';
135
+ }
136
+ isMainEntry(key) {
137
+ return key.startsWith('worker/') && key.endsWith('/ac');
138
+ }
139
+ isHookEntry(key) {
140
+ return key.startsWith('hook_worker/') && key.endsWith('/ac');
141
+ }
142
+ /**
143
+ * Inflates the key from Redis, 3-character symbol
144
+ * into a human-readable JSON path, reflecting the
145
+ * tree-like structure of the unidimensional Hash
146
+ */
147
+ inflateKey(key) {
148
+ if (key in this.symbols) {
149
+ const path = this.symbols[key];
150
+ const parts = path.split('/');
151
+ if (parts[0] in this.activitySymbols) {
152
+ parts[0] = this.activitySymbols[parts[0]];
153
+ }
154
+ return parts.join('/');
155
+ }
156
+ return key;
157
+ }
158
+ /**
159
+ * Inflates the dependency data from Redis into a DurableJobExport object by
160
+ * organizing the dimensional isolate in sch a way asto interleave
161
+ * into a story
162
+ * @param data - the dependency data from Redis
163
+ * @returns - the organized dependency data
164
+ */
165
+ inflateDependencyData(data, actions) {
166
+ //console.log('dependency data>', data);
167
+ const hookReg = /([0-9,]+)-(\d+)$/;
168
+ const flowReg = /-(\d+)$/;
169
+ return data.map((dependency, index) => {
170
+ const [action, topic, gid, ...jid] = dependency.split('::');
171
+ const jobId = jid.join('::');
172
+ const match = jobId.match(hookReg);
173
+ let prefix;
174
+ let type;
175
+ let dimensionKey = '';
176
+ if (match) {
177
+ //hook-originating dependency
178
+ const [_, dimension, counter] = match;
179
+ dimensionKey = dimension.split(',').join('/');
180
+ prefix = `${dimensionKey}[${counter}]`;
181
+ type = 'hook';
182
+ }
183
+ else {
184
+ const match = jobId.match(flowReg);
185
+ if (match) {
186
+ //main workflow-originating dependency
187
+ const [_, counter] = match;
188
+ prefix = `[${counter}]`;
189
+ type = 'flow';
190
+ }
191
+ else {
192
+ //'other' types like signal cleanup
193
+ prefix = '/';
194
+ type = 'other';
195
+ }
196
+ }
197
+ this.seedActions(type, action, topic, dependency, prefix, dimensionKey, actions, jobId);
198
+ return {
199
+ type: action,
200
+ topic,
201
+ gid,
202
+ jid: jobId,
203
+ };
204
+ });
205
+ }
206
+ /**
207
+ * Adds historical actions (proxyActivity, executeChild)
208
+ * using the `dependency list` to determine
209
+ * after-the-fact what happened within the 'black-box'
210
+ * worker function. This is necessary to interleave the
211
+ * actions into the replay timeline, given that it isn't
212
+ * really possible to know the inner-workings of the user's
213
+ * function
214
+ *
215
+ */
216
+ seedActions(type, action, topic, dep, prefix, dimensionKey, actions, jobId) {
217
+ if (type !== 'other' && action === 'expire-child') {
218
+ let depType;
219
+ if (topic == `${this.appId}.activity.execute`) {
220
+ depType = 'proxyActivity';
221
+ }
222
+ else if (topic == `${this.appId}.execute`) {
223
+ depType = 'executeChild';
224
+ }
225
+ else if (topic == `${this.appId}.wfsc.execute`) {
226
+ depType = 'waitForSignal';
227
+ }
228
+ if (depType) {
229
+ if (type === 'flow') {
230
+ actions.main.items.push([prefix, depType, jobId]);
231
+ }
232
+ else if (type === 'hook') {
233
+ if (!actions.hooks[dimensionKey]) {
234
+ actions.hooks[dimensionKey] = {
235
+ cursor: -1,
236
+ items: [],
237
+ };
238
+ }
239
+ actions.hooks[dimensionKey].items.push([prefix, depType, jobId]);
240
+ }
241
+ }
242
+ }
243
+ }
244
+ /**
245
+ * Inflates the job data from Redis into a DurableJobExport object
246
+ * @param jobHash - the job data from Redis
247
+ * @param dependencyList - the list of dependencies for the job
248
+ * @returns - the inflated job data
249
+ */
250
+ inflate(jobHash, dependencyList) {
251
+ //the list of actions taken in the workflow and hook functions
252
+ const actions = {
253
+ hooks: {},
254
+ main: { cursor: -1, items: [] },
255
+ };
256
+ const dependencies = this.inflateDependencyData(dependencyList, actions);
257
+ const state = {};
258
+ const data = {};
259
+ const other = [];
260
+ const replay = [];
261
+ const regex = /^([a-zA-Z]{3}),(\d+(?:,\d+)*)/;
262
+ Object.entries(jobHash).forEach(([key, value]) => {
263
+ const match = key.match(regex);
264
+ if (match) {
265
+ //activity process state
266
+ this.inflateProcess(match, value, replay);
267
+ }
268
+ else if (key.length === 3) {
269
+ //job state
270
+ state[this.inflateKey(key)] = this.serializer.fromString(value);
271
+ }
272
+ else if (key.startsWith('_')) {
273
+ //job data
274
+ data[key.substring(1)] = value;
275
+ }
276
+ else if (key.startsWith('-')) {
277
+ //actions with side effect (replayable)
278
+ this.inflateActions(key, value, actions);
279
+ }
280
+ else {
281
+ //collator guids, etc
282
+ other.push([null, key, value]);
283
+ }
284
+ });
285
+ replay.sort(this.dateSort);
286
+ actions.main.items.sort(this.reverseSort);
287
+ Object.entries(actions.hooks).forEach(([key, value]) => {
288
+ value.items.sort(this.reverseSort);
289
+ });
290
+ return {
291
+ data: (0, utils_1.restoreHierarchy)(data),
292
+ dependencies,
293
+ state: Object.entries((0, utils_1.restoreHierarchy)(state))[0][1],
294
+ status: jobHash[':'],
295
+ timeline: this.createTimeline(replay, actions),
296
+ transitions: { ...this.transitions },
297
+ cycles: { ...this.cycles },
298
+ };
299
+ }
300
+ inflateProcess(match, value, replay) {
301
+ const [_, letters, numbers] = match;
302
+ const path = this.inflateKey(letters);
303
+ if (path.endsWith('/output/metadata/ac') ||
304
+ path.endsWith('/output/metadata/au')) {
305
+ const dimensions = `/${numbers.replace(/,/g, '/')}`;
306
+ const resolved = this.serializer.fromString(value);
307
+ replay.push([
308
+ dimensions,
309
+ path,
310
+ resolved,
311
+ ]);
312
+ }
313
+ }
314
+ inflateActions(key, value, actions) {
315
+ let [_, dimensionalType, counter, subcounter] = key.split('-');
316
+ if (subcounter) {
317
+ counter = `${counter}.${subcounter}`;
318
+ }
319
+ const [type, ...dimensions] = dimensionalType.split(',');
320
+ let dimensionKey = '';
321
+ let isHook = false;
322
+ if (dimensions.length > 0) {
323
+ dimensionKey = `/${dimensions.join('/')}`;
324
+ isHook = true;
325
+ }
326
+ let targetList;
327
+ if (isHook) {
328
+ if (!actions.hooks[dimensionKey]) {
329
+ actions.hooks[dimensionKey] = {
330
+ cursor: -1,
331
+ items: [],
332
+ };
333
+ }
334
+ targetList = actions.hooks[dimensionKey].items;
335
+ }
336
+ else {
337
+ targetList = actions.main.items;
338
+ }
339
+ targetList.push([
340
+ `${dimensionKey}[${counter}]`,
341
+ type,
342
+ value,
343
+ ]);
344
+ }
345
+ reverseSort(aKey, bKey) {
346
+ if (aKey[0] > bKey[0]) {
347
+ return 1;
348
+ }
349
+ else if (aKey[0] < bKey[0]) {
350
+ return -1;
351
+ }
352
+ else {
353
+ if (aKey[1] > bKey[1]) {
354
+ return 1;
355
+ }
356
+ else if (aKey[1] < bKey[1]) {
357
+ return -1;
358
+ }
359
+ return 0;
360
+ }
361
+ }
362
+ dateSort(aKey, bKey) {
363
+ if (aKey[2] > bKey[2]) {
364
+ return 1;
365
+ }
366
+ else if (aKey[2] < bKey[2]) {
367
+ return -1;
368
+ }
369
+ else {
370
+ return 0;
371
+ }
372
+ }
373
+ }
374
+ exports.ExporterService = ExporterService;
@@ -60,6 +60,7 @@ const getWorkflowYAML = (app, version) => {
60
60
  id: '{$self.input.data.workflowId}'
61
61
  key: '{$self.input.data.parentWorkflowId}'
62
62
  parent: '{$self.input.data.originJobId}'
63
+ adjacent: '{$self.input.data.parentWorkflowId}'
63
64
  job:
64
65
  maps:
65
66
  done: false
@@ -263,10 +264,7 @@ const getWorkflowYAML = (app, version) => {
263
264
  description: index will be appended later
264
265
  maps:
265
266
  signals: '{sigw1.output.data.signals}'
266
- parentWorkflowId:
267
- '@pipe':
268
- - ['{$job.metadata.jid}', '-w']
269
- - ['{@string.concat}']
267
+ parentWorkflowId: '{$job.metadata.jid}'
270
268
  originJobId:
271
269
  '@pipe':
272
270
  - ['{t1.output.data.originJobId}', '{t1.output.data.originJobId}', '{$job.metadata.jid}']
@@ -356,10 +354,7 @@ const getWorkflowYAML = (app, version) => {
356
354
  description: index will be appended later
357
355
  maps:
358
356
  signals: '{w1.output.data.signals}'
359
- parentWorkflowId:
360
- '@pipe':
361
- - ['{$job.metadata.jid}', '-w']
362
- - ['{@string.concat}']
357
+ parentWorkflowId: '{$job.metadata.jid}'
363
358
  originJobId:
364
359
  '@pipe':
365
360
  - ['{t1.output.data.originJobId}', '{t1.output.data.originJobId}', '{$job.metadata.jid}']
@@ -526,6 +521,7 @@ const getWorkflowYAML = (app, version) => {
526
521
  id: '{$self.input.data.workflowId}'
527
522
  key: '{$self.input.data.parentWorkflowId}'
528
523
  parent: '{$self.input.data.originJobId}'
524
+ adjacent: '{$self.input.data.parentWorkflowId}'
529
525
 
530
526
  w1a:
531
527
  title: Activity Worker - Calls Activity Functions
@@ -566,61 +562,6 @@ const getWorkflowYAML = (app, version) => {
566
562
  t1a:
567
563
  - to: w1a
568
564
 
569
- - subscribes: ${app}.sleep.execute
570
- publishes: ${app}.sleep.executed
571
-
572
- expire: 0
573
-
574
- input:
575
- schema:
576
- type: object
577
- properties:
578
- parentWorkflowId:
579
- type: string
580
- originJobId:
581
- type: string
582
- workflowId:
583
- type: string
584
- duration:
585
- type: number
586
- description: in seconds
587
- index:
588
- type: number
589
- output:
590
- schema:
591
- type: object
592
- properties:
593
- done:
594
- type: boolean
595
- duration:
596
- type: number
597
- index:
598
- type: number
599
-
600
- activities:
601
- t1s:
602
- title: Sleep Flow Trigger
603
- type: trigger
604
- stats:
605
- id: '{$self.input.data.workflowId}'
606
- key: '{$self.input.data.parentWorkflowId}'
607
- parent: '{$self.input.data.originJobId}'
608
-
609
- a1s:
610
- title: Sleep for a duration
611
- type: hook
612
- sleep: '{t1s.output.data.duration}'
613
- job:
614
- maps:
615
- done: true
616
- duration: '{t1s.output.data.duration}'
617
- index: '{t1s.output.data.index}'
618
- workflowId: '{t1s.output.data.workflowId}'
619
-
620
- transitions:
621
- t1s:
622
- - to: a1s
623
-
624
565
  - subscribes: ${app}.wfsc.execute
625
566
  publishes: ${app}.wfsc.executed
626
567
 
@@ -665,6 +606,7 @@ const getWorkflowYAML = (app, version) => {
665
606
  stats:
666
607
  id: '{$self.input.data.cycleWorkflowId}'
667
608
  parent: '{$self.input.data.originJobId}'
609
+ adjacent: '{$self.input.data.parentWorkflowId}'
668
610
 
669
611
  a1wc:
670
612
  title: Pivot - All Cycling Descendants Point Here
@@ -836,6 +778,7 @@ const getWorkflowYAML = (app, version) => {
836
778
  id: '{$self.input.data.workflowId}'
837
779
  key: '{$self.input.data.parentWorkflowId}'
838
780
  parent: '{$self.input.data.originJobId}'
781
+ adjacent: '{$self.input.data.parentWorkflowId}'
839
782
 
840
783
  a1ww:
841
784
  title: WFS - signal entry point
@@ -1,10 +1,14 @@
1
+ import { ExporterService } from './exporter';
1
2
  import { HotMeshService as HotMesh } from '../hotmesh';
3
+ import { DurableJobExport } from '../../types/exporter';
2
4
  import { JobInterruptOptions } from '../../types/job';
3
5
  export declare class WorkflowHandleService {
6
+ exporter: ExporterService;
4
7
  hotMesh: HotMesh;
5
8
  workflowTopic: string;
6
9
  workflowId: string;
7
10
  constructor(hotMesh: HotMesh, workflowTopic: string, workflowId: string);
11
+ export(): Promise<DurableJobExport>;
8
12
  /**
9
13
  * Sends a signal to the workflow. This is a way to send
10
14
  * a message to a workflow that is paused due to having
@@ -2,11 +2,16 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WorkflowHandleService = void 0;
4
4
  const enums_1 = require("../../modules/enums");
5
+ const exporter_1 = require("./exporter");
5
6
  class WorkflowHandleService {
6
7
  constructor(hotMesh, workflowTopic, workflowId) {
7
8
  this.workflowTopic = workflowTopic;
8
9
  this.workflowId = workflowId;
9
10
  this.hotMesh = hotMesh;
11
+ this.exporter = new exporter_1.ExporterService(this.hotMesh.appId, this.hotMesh.engine.store, this.hotMesh.engine.logger);
12
+ }
13
+ async export() {
14
+ return this.exporter.export(this.workflowId);
10
15
  }
11
16
  /**
12
17
  * Sends a signal to the workflow. This is a way to send