@hotmeshio/hotmesh 0.0.16 → 0.0.17

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/hotmesh",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
4
  "description": "Unbreakable Workflows",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -496,7 +496,12 @@ class Activity {
496
496
  }
497
497
  async transition(adjacencyList, jobStatus) {
498
498
  let mIds = [];
499
- if (jobStatus <= 0 || this.config.emit) {
499
+ //emit can be a mapping (allows emissions to be driven by the job state)
500
+ let emit = false;
501
+ if (this.config.emit) {
502
+ emit = pipe_1.Pipe.resolve(this.config.emit, this.context);
503
+ }
504
+ if (jobStatus <= 0 || emit) {
500
505
  //activity should not send 'emit' if the job is truly over
501
506
  const isTrueEmit = jobStatus > 0;
502
507
  await this.engine.runJobCompletionTasks(this.context, isTrueEmit);
@@ -151,7 +151,7 @@ class Trigger extends activity_1.Activity {
151
151
  }
152
152
  async setStats(multi) {
153
153
  const md = this.context.metadata;
154
- if (this.config.stats?.measures) {
154
+ if (md.key && this.config.stats?.measures) {
155
155
  const config = await this.engine.getVID();
156
156
  const reporter = new reporter_1.ReporterService(config, this.store, this.logger);
157
157
  await this.store.setStats(md.key, md.jid, md.ts, reporter.resolveTriggerStatistics(this.config, this.context), config, multi);
@@ -87,6 +87,7 @@ class ClientService {
87
87
  const hotMeshClient = await this.getHotMeshClient(workflowTopic);
88
88
  const payload = {
89
89
  arguments: [...options.args],
90
+ parentWorkflowId: options.parentWorkflowId,
90
91
  workflowId: options.workflowId || (0, nanoid_1.nanoid)(),
91
92
  workflowTopic: workflowTopic,
92
93
  backoffCoefficient: options.config?.backoffCoefficient || factory_1.DEFAULT_COEFFICIENT,
@@ -25,6 +25,8 @@ const getWorkflowYAML = (app, version) => {
25
25
  schema:
26
26
  type: object
27
27
  properties:
28
+ parentWorkflowId:
29
+ type: string
28
30
  workflowId:
29
31
  type: string
30
32
  arguments:
@@ -47,6 +49,11 @@ const getWorkflowYAML = (app, version) => {
47
49
  type: trigger
48
50
  stats:
49
51
  id: '{$self.input.data.workflowId}'
52
+ key: '{$self.input.data.parentWorkflowId}'
53
+ granularity: infinity
54
+ measures:
55
+ - measure: index
56
+ target: '{$self.input.data.parentWorkflowId}'
50
57
  job:
51
58
  maps:
52
59
  done: false
@@ -66,6 +73,7 @@ const getWorkflowYAML = (app, version) => {
66
73
  w1:
67
74
  type: worker
68
75
  topic: '{t1.output.data.workflowTopic}'
76
+ emit: '{$job.data.done}'
69
77
  retry:
70
78
  '599': [2]
71
79
  input:
@@ -123,6 +131,19 @@ const getWorkflowYAML = (app, version) => {
123
131
  response: '{$self.output.data.response}'
124
132
  done: '{$self.output.data.done}'
125
133
 
134
+ a2:
135
+ type: activity
136
+ title: Wait for cleanup signal
137
+ hook:
138
+ type: object
139
+ properties:
140
+ done:
141
+ type: boolean
142
+ job:
143
+ maps:
144
+ workflowId: '{t1.output.data.workflowId}'
145
+
146
+
126
147
  a594:
127
148
  title: Wait for signals
128
149
  type: await
@@ -280,7 +301,7 @@ const getWorkflowYAML = (app, version) => {
280
301
  done: true
281
302
 
282
303
  s2:
283
- title: Awaken sleep flows so they end and self-clean
304
+ title: Awaken sleeping flows so they end and self-clean
284
305
  type: signal
285
306
  subtype: all
286
307
  key_name: parentWorkflowId
@@ -352,10 +373,55 @@ const getWorkflowYAML = (app, version) => {
352
373
  type: boolean
353
374
  maps:
354
375
  done: true
376
+
377
+ s4:
378
+ title: Awaken child FLOWS so they end and self-clean
379
+ type: signal
380
+ subtype: all
381
+ key_name: parentWorkflowId
382
+ key_value:
383
+ '@pipe':
384
+ - ['{$job.metadata.jid}', '-f']
385
+ - ['{@string.concat}']
386
+ topic: ${app}.childflow.awaken
387
+ resolver:
388
+ schema:
389
+ type: object
390
+ properties:
391
+ data:
392
+ type: object
393
+ properties:
394
+ parentWorkflowId:
395
+ type: string
396
+ scrub:
397
+ type: boolean
398
+ maps:
399
+ data:
400
+ parentWorkflowId:
401
+ '@pipe':
402
+ - ['{$job.metadata.jid}', '-f']
403
+ - ['{@string.concat}']
404
+ scrub: true
405
+ signal:
406
+ schema:
407
+ type: object
408
+ properties:
409
+ done:
410
+ type: boolean
411
+ maps:
412
+ done: true
355
413
 
356
414
  transitions:
357
415
  t1:
358
416
  - to: a1
417
+ - to: a2
418
+ conditions:
419
+ match:
420
+ - expected: true
421
+ actual:
422
+ '@pipe':
423
+ - ['{$job.metadata.key}', true, false]
424
+ - ['{@conditional.ternary}']
359
425
  a1:
360
426
  - to: w1
361
427
  w1:
@@ -377,11 +443,13 @@ const getWorkflowYAML = (app, version) => {
377
443
  - to: s3
378
444
  conditions:
379
445
  code: [200, 598, 597, 596]
446
+ - to: s4
447
+ conditions:
448
+ code: [200, 598, 597, 596]
380
449
  a594:
381
450
  - to: c594
382
451
  conditions:
383
452
  code: 202
384
-
385
453
  a595:
386
454
  - to: c595
387
455
  conditions:
@@ -389,6 +457,14 @@ const getWorkflowYAML = (app, version) => {
389
457
  a599:
390
458
  - to: c599
391
459
 
460
+ hooks:
461
+ ${app}.childflow.awaken:
462
+ - to: a2
463
+ conditions:
464
+ match:
465
+ - expected: '{t1.output.data.workflowId}'
466
+ actual: '{$self.hook.data.id}'
467
+
392
468
  - subscribes: ${app}.activity.execute
393
469
  publishes: ${app}.activity.executed
394
470
 
@@ -54,6 +54,7 @@ class WorkflowService {
54
54
  const COUNTER = store.get('counter');
55
55
  const execIndex = COUNTER.counter = COUNTER.counter + 1;
56
56
  const childJobId = `${workflowId}-$${options.workflowName}-${execIndex}`;
57
+ const parentWorkflowId = `${workflowId}-f`;
57
58
  const client = new client_1.ClientService({
58
59
  connection: await connection_1.ConnectionService.connect(worker_1.WorkerService.connection),
59
60
  });
@@ -65,6 +66,7 @@ class WorkflowService {
65
66
  handle = await client.workflow.start({
66
67
  ...options,
67
68
  workflowId: childJobId,
69
+ parentWorkflowId,
68
70
  workflowTrace,
69
71
  workflowSpan,
70
72
  });
@@ -10,6 +10,7 @@ type WorkflowOptions = {
10
10
  args: any[];
11
11
  workflowId: string;
12
12
  workflowName?: string;
13
+ parentWorkflowId?: string;
13
14
  workflowTrace?: string;
14
15
  workflowSpan?: string;
15
16
  config?: WorkflowConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/hotmesh",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
4
  "description": "Unbreakable Workflows",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -584,7 +584,12 @@ class Activity {
584
584
 
585
585
  async transition(adjacencyList: StreamData[], jobStatus: JobStatus): Promise<string[]> {
586
586
  let mIds: string[] = [];
587
- if (jobStatus <= 0 || this.config.emit) {
587
+ //emit can be a mapping (allows emissions to be driven by the job state)
588
+ let emit: boolean = false;
589
+ if (this.config.emit) {
590
+ emit = Pipe.resolve(this.config.emit, this.context);
591
+ }
592
+ if (jobStatus <= 0 || emit) {
588
593
  //activity should not send 'emit' if the job is truly over
589
594
  const isTrueEmit = jobStatus > 0;
590
595
  await this.engine.runJobCompletionTasks(this.context, isTrueEmit);
@@ -178,7 +178,7 @@ class Trigger extends Activity {
178
178
 
179
179
  async setStats(multi?: RedisMulti): Promise<void> {
180
180
  const md = this.context.metadata;
181
- if (this.config.stats?.measures) {
181
+ if (md.key && this.config.stats?.measures) {
182
182
  const config = await this.engine.getVID();
183
183
  const reporter = new ReporterService(config, this.store, this.logger);
184
184
  await this.store.setStats(
@@ -101,6 +101,7 @@ export class ClientService {
101
101
  const hotMeshClient = await this.getHotMeshClient(workflowTopic);
102
102
  const payload = {
103
103
  arguments: [...options.args],
104
+ parentWorkflowId: options.parentWorkflowId,
104
105
  workflowId: options.workflowId || nanoid(),
105
106
  workflowTopic: workflowTopic,
106
107
  backoffCoefficient: options.config?.backoffCoefficient || DEFAULT_COEFFICIENT,
@@ -24,6 +24,8 @@ const getWorkflowYAML = (app: string, version: string) => {
24
24
  schema:
25
25
  type: object
26
26
  properties:
27
+ parentWorkflowId:
28
+ type: string
27
29
  workflowId:
28
30
  type: string
29
31
  arguments:
@@ -46,6 +48,11 @@ const getWorkflowYAML = (app: string, version: string) => {
46
48
  type: trigger
47
49
  stats:
48
50
  id: '{$self.input.data.workflowId}'
51
+ key: '{$self.input.data.parentWorkflowId}'
52
+ granularity: infinity
53
+ measures:
54
+ - measure: index
55
+ target: '{$self.input.data.parentWorkflowId}'
49
56
  job:
50
57
  maps:
51
58
  done: false
@@ -65,6 +72,7 @@ const getWorkflowYAML = (app: string, version: string) => {
65
72
  w1:
66
73
  type: worker
67
74
  topic: '{t1.output.data.workflowTopic}'
75
+ emit: '{$job.data.done}'
68
76
  retry:
69
77
  '599': [2]
70
78
  input:
@@ -122,6 +130,19 @@ const getWorkflowYAML = (app: string, version: string) => {
122
130
  response: '{$self.output.data.response}'
123
131
  done: '{$self.output.data.done}'
124
132
 
133
+ a2:
134
+ type: activity
135
+ title: Wait for cleanup signal
136
+ hook:
137
+ type: object
138
+ properties:
139
+ done:
140
+ type: boolean
141
+ job:
142
+ maps:
143
+ workflowId: '{t1.output.data.workflowId}'
144
+
145
+
125
146
  a594:
126
147
  title: Wait for signals
127
148
  type: await
@@ -279,7 +300,7 @@ const getWorkflowYAML = (app: string, version: string) => {
279
300
  done: true
280
301
 
281
302
  s2:
282
- title: Awaken sleep flows so they end and self-clean
303
+ title: Awaken sleeping flows so they end and self-clean
283
304
  type: signal
284
305
  subtype: all
285
306
  key_name: parentWorkflowId
@@ -351,10 +372,55 @@ const getWorkflowYAML = (app: string, version: string) => {
351
372
  type: boolean
352
373
  maps:
353
374
  done: true
375
+
376
+ s4:
377
+ title: Awaken child FLOWS so they end and self-clean
378
+ type: signal
379
+ subtype: all
380
+ key_name: parentWorkflowId
381
+ key_value:
382
+ '@pipe':
383
+ - ['{$job.metadata.jid}', '-f']
384
+ - ['{@string.concat}']
385
+ topic: ${app}.childflow.awaken
386
+ resolver:
387
+ schema:
388
+ type: object
389
+ properties:
390
+ data:
391
+ type: object
392
+ properties:
393
+ parentWorkflowId:
394
+ type: string
395
+ scrub:
396
+ type: boolean
397
+ maps:
398
+ data:
399
+ parentWorkflowId:
400
+ '@pipe':
401
+ - ['{$job.metadata.jid}', '-f']
402
+ - ['{@string.concat}']
403
+ scrub: true
404
+ signal:
405
+ schema:
406
+ type: object
407
+ properties:
408
+ done:
409
+ type: boolean
410
+ maps:
411
+ done: true
354
412
 
355
413
  transitions:
356
414
  t1:
357
415
  - to: a1
416
+ - to: a2
417
+ conditions:
418
+ match:
419
+ - expected: true
420
+ actual:
421
+ '@pipe':
422
+ - ['{$job.metadata.key}', true, false]
423
+ - ['{@conditional.ternary}']
358
424
  a1:
359
425
  - to: w1
360
426
  w1:
@@ -376,11 +442,13 @@ const getWorkflowYAML = (app: string, version: string) => {
376
442
  - to: s3
377
443
  conditions:
378
444
  code: [200, 598, 597, 596]
445
+ - to: s4
446
+ conditions:
447
+ code: [200, 598, 597, 596]
379
448
  a594:
380
449
  - to: c594
381
450
  conditions:
382
451
  code: 202
383
-
384
452
  a595:
385
453
  - to: c595
386
454
  conditions:
@@ -388,6 +456,14 @@ const getWorkflowYAML = (app: string, version: string) => {
388
456
  a599:
389
457
  - to: c599
390
458
 
459
+ hooks:
460
+ ${app}.childflow.awaken:
461
+ - to: a2
462
+ conditions:
463
+ match:
464
+ - expected: '{t1.output.data.workflowId}'
465
+ actual: '{$self.hook.data.id}'
466
+
391
467
  - subscribes: ${app}.activity.execute
392
468
  publishes: ${app}.activity.executed
393
469
 
@@ -54,6 +54,7 @@ export class WorkflowService {
54
54
  const COUNTER = store.get('counter');
55
55
  const execIndex = COUNTER.counter = COUNTER.counter + 1;
56
56
  const childJobId = `${workflowId}-$${options.workflowName}-${execIndex}`;
57
+ const parentWorkflowId = `${workflowId}-f`;
57
58
 
58
59
  const client = new Client({
59
60
  connection: await Connection.connect(WorkerService.connection),
@@ -71,6 +72,7 @@ export class WorkflowService {
71
72
  handle = await client.workflow.start({
72
73
  ...options,
73
74
  workflowId: childJobId,
75
+ parentWorkflowId,
74
76
  workflowTrace,
75
77
  workflowSpan,
76
78
  });
package/types/durable.ts CHANGED
@@ -12,6 +12,7 @@ type WorkflowOptions = {
12
12
  args: any[]; //input arguments to pass in
13
13
  workflowId: string; //execution id (the job id)
14
14
  workflowName?: string; //the name of the user's workflow function
15
+ parentWorkflowId?: string; //system reserved; the id of the parent; if present the flow will not self-clean until the parent that spawned it self-cleans
15
16
  workflowTrace?: string;
16
17
  workflowSpan?: string;
17
18
  config?: WorkflowConfig;