@hotmeshio/hotmesh 0.0.19 → 0.0.21

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 (58) hide show
  1. package/README.md +4 -4
  2. package/build/modules/errors.d.ts +2 -1
  3. package/build/modules/errors.js +2 -1
  4. package/build/package.json +2 -1
  5. package/build/services/activities/activity.d.ts +2 -2
  6. package/build/services/activities/activity.js +10 -8
  7. package/build/services/activities/hook.d.ts +2 -1
  8. package/build/services/activities/hook.js +12 -9
  9. package/build/services/activities/signal.d.ts +4 -0
  10. package/build/services/activities/signal.js +16 -2
  11. package/build/services/durable/client.d.ts +15 -5
  12. package/build/services/durable/client.js +37 -14
  13. package/build/services/durable/factory.d.ts +2 -16
  14. package/build/services/durable/factory.js +276 -46
  15. package/build/services/durable/handle.d.ts +1 -1
  16. package/build/services/durable/handle.js +18 -5
  17. package/build/services/durable/search.d.ts +8 -1
  18. package/build/services/durable/search.js +36 -10
  19. package/build/services/durable/worker.d.ts +7 -9
  20. package/build/services/durable/worker.js +29 -23
  21. package/build/services/durable/workflow.d.ts +23 -2
  22. package/build/services/durable/workflow.js +143 -37
  23. package/build/services/engine/index.d.ts +2 -2
  24. package/build/services/engine/index.js +7 -12
  25. package/build/services/hotmesh/index.d.ts +2 -2
  26. package/build/services/hotmesh/index.js +2 -2
  27. package/build/services/signaler/store.d.ts +2 -2
  28. package/build/services/signaler/store.js +17 -7
  29. package/build/services/signaler/stream.js +1 -0
  30. package/build/services/store/clients/redis.js +1 -1
  31. package/build/services/store/index.js +3 -0
  32. package/build/services/telemetry/index.js +7 -1
  33. package/build/types/activity.d.ts +5 -3
  34. package/build/types/durable.d.ts +13 -2
  35. package/build/types/hook.d.ts +0 -1
  36. package/build/types/index.d.ts +1 -1
  37. package/modules/errors.ts +4 -2
  38. package/package.json +2 -1
  39. package/services/activities/activity.ts +10 -8
  40. package/services/activities/hook.ts +13 -10
  41. package/services/activities/signal.ts +17 -3
  42. package/services/durable/client.ts +40 -15
  43. package/services/durable/factory.ts +274 -46
  44. package/services/durable/handle.ts +18 -5
  45. package/services/durable/search.ts +38 -10
  46. package/services/durable/worker.ts +30 -24
  47. package/services/durable/workflow.ts +158 -40
  48. package/services/engine/index.ts +8 -12
  49. package/services/hotmesh/index.ts +3 -3
  50. package/services/signaler/store.ts +18 -8
  51. package/services/signaler/stream.ts +1 -0
  52. package/services/store/clients/redis.ts +1 -1
  53. package/services/store/index.ts +2 -0
  54. package/services/telemetry/index.ts +6 -1
  55. package/types/activity.ts +10 -8
  56. package/types/durable.ts +14 -1
  57. package/types/hook.ts +0 -1
  58. package/types/index.ts +1 -0
@@ -1,18 +1,16 @@
1
1
  "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_COEFFICIENT = exports.APP_ID = exports.APP_VERSION = exports.getWorkflowYAML = void 0;
2
4
  /**
3
5
  * NOTE: Using `maxSystemRetries = 3` and `backoffCoefficient = 10`, errant
4
6
  * workflows will be retried on the following schedule (8 times in 27 hours):
5
7
  * => 10ms, 100ms, 1000ms, 10s, 100s, 1_000s, 10_000s, 100_000s
6
- * 593:
8
+ *
7
9
  * 594: waitforsignal
8
10
  * 595: sleep
9
11
  * 596, 597, 598: fatal
10
12
  * 599: retry
11
13
  */
12
- Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.WFS_HOOK_ID = exports.WFSC_PUBLISHES_TOPIC = exports.WFSC_SUBSCRIBES_TOPIC = exports.WFS_PUBLISHES_TOPIC = exports.WFS_SUBSCRIBES_TOPIC = exports.DEFAULT_COEFFICIENT = exports.SLEEP_HOOK_ID = exports.ACTIVITY_HOOK_ID = exports.HOOK_ID = exports.PUBLISHES_TOPIC = exports.SUBSCRIBES_TOPIC = exports.SLEEP_PUBLISHES_TOPIC = exports.SLEEP_SUBSCRIBES_TOPIC = exports.ACTIVITY_PUBLISHES_TOPIC = exports.ACTIVITY_SUBSCRIBES_TOPIC = exports.APP_ID = exports.APP_VERSION = exports.getWorkflowYAML = void 0;
14
- //todo: getChildWorkflowYAML (includes key, so flow will cleanup)
15
- //todo: if an activity throws an error, it should self-clean its index
16
14
  const getWorkflowYAML = (app, version) => {
17
15
  return `app:
18
16
  id: ${app}
@@ -46,6 +44,7 @@ const getWorkflowYAML = (app, version) => {
46
44
 
47
45
  activities:
48
46
  t1:
47
+ title: Main Flow Trigger
49
48
  type: trigger
50
49
  stats:
51
50
  id: '{$self.input.data.workflowId}'
@@ -59,6 +58,7 @@ const getWorkflowYAML = (app, version) => {
59
58
  done: false
60
59
 
61
60
  a1:
61
+ title: Main Flow Pivot - All Cycling Descendants Point Here
62
62
  type: hook
63
63
  cycle: true
64
64
  output:
@@ -71,6 +71,7 @@ const getWorkflowYAML = (app, version) => {
71
71
  duration: '{t1.output.data.backoffCoefficient}'
72
72
 
73
73
  w1:
74
+ title: Main Worker - Calls Workflow Functions
74
75
  type: worker
75
76
  topic: '{t1.output.data.workflowTopic}'
76
77
  emit: '{$job.data.done}'
@@ -132,8 +133,8 @@ const getWorkflowYAML = (app, version) => {
132
133
  done: '{$self.output.data.done}'
133
134
 
134
135
  a2:
135
- type: hook
136
136
  title: Wait for cleanup signal
137
+ type: hook
137
138
  hook:
138
139
  type: object
139
140
  properties:
@@ -143,6 +144,209 @@ const getWorkflowYAML = (app, version) => {
143
144
  maps:
144
145
  workflowId: '{t1.output.data.workflowId}'
145
146
 
147
+ sig:
148
+ title: Signal In - Receive signals
149
+ type: hook
150
+ hook:
151
+ type: object
152
+ properties:
153
+ id:
154
+ type: string
155
+ arguments:
156
+ type: array
157
+ workflowTopic:
158
+ type: string
159
+ job:
160
+ maps:
161
+ workflowId: '{t1.output.data.workflowId}'
162
+
163
+ siga1:
164
+ title: Signal In Flow Pivot - Cycling Descendants Point Here
165
+ type: hook
166
+ cycle: true
167
+ output:
168
+ schema:
169
+ type: object
170
+ properties:
171
+ duration:
172
+ type: number
173
+ maps:
174
+ duration: '{t1.output.data.backoffCoefficient}'
175
+
176
+ sigw1:
177
+ title: Signal In - Worker
178
+ type: worker
179
+ topic: '{sig.hook.data.workflowTopic}'
180
+ retry:
181
+ '599': [2]
182
+ input:
183
+ schema:
184
+ type: object
185
+ properties:
186
+ workflowId:
187
+ type: string
188
+ workflowDimension:
189
+ type: string
190
+ arguments:
191
+ type: array
192
+ maps:
193
+ workflowId: '{t1.output.data.workflowId}'
194
+ workflowDimension: '{sig.output.metadata.dad}'
195
+ arguments: '{sig.hook.data.arguments}'
196
+ output:
197
+ schema:
198
+ type: object
199
+ 594:
200
+ schema:
201
+ type: object
202
+ properties:
203
+ index:
204
+ type: number
205
+ description: the index of the first signal in the array
206
+ signals:
207
+ type: array
208
+ description: remaining signal ids
209
+ items:
210
+ type: object
211
+ properties:
212
+ signal:
213
+ type: string
214
+ index:
215
+ type: number
216
+ maps:
217
+ index: '{$self.output.data.index}'
218
+ signals: '{$self.output.data.signals}'
219
+ 595:
220
+ schema:
221
+ type: object
222
+ properties:
223
+ duration:
224
+ type: number
225
+ description: sleep duration in seconds
226
+ index:
227
+ type: number
228
+ description: the current index
229
+ maps:
230
+ duration: '{$self.output.data.duration}'
231
+ index: '{$self.output.data.index}'
232
+
233
+ siga594:
234
+ title: Signal In - Wait for signals
235
+ type: await
236
+ topic: ${app}.wfsc.execute
237
+ input:
238
+ schema:
239
+ type: object
240
+ properties:
241
+ index:
242
+ type: number
243
+ signals:
244
+ type: array
245
+ description: signal ids
246
+ items:
247
+ type: object
248
+ properties:
249
+ signal:
250
+ type: string
251
+ index:
252
+ type: number
253
+ parentWorkflowId:
254
+ type: string
255
+ cycleWorkflowId:
256
+ type: string
257
+ baseWorkflowId:
258
+ type: string
259
+ description: index will be appended later
260
+ maps:
261
+ signals: '{sigw1.output.data.signals}'
262
+ parentWorkflowId:
263
+ '@pipe':
264
+ - ['{$job.metadata.jid}', '-w']
265
+ - ['{@string.concat}']
266
+ cycleWorkflowId:
267
+ '@pipe':
268
+ - ['{$job.metadata.jid}', '-$wfc', '{sig.output.metadata.dad}', '-', '{sigw1.output.data.index}']
269
+ - ['{@string.concat}']
270
+ baseWorkflowId:
271
+ '@pipe':
272
+ - ['{$job.metadata.jid}', '-$wfs', '{sig.output.metadata.dad}', '-']
273
+ - ['{@string.concat}']
274
+ output:
275
+ schema:
276
+ type: object
277
+ properties:
278
+ done:
279
+ type: boolean
280
+ maps:
281
+ done: '{sigw1.output.data.done}'
282
+
283
+ sigc594:
284
+ title: Signal In - Goto Activity siga1
285
+ type: cycle
286
+ ancestor: siga1
287
+ input:
288
+ maps:
289
+ duration: '{siga1.output.data.duration}'
290
+
291
+ siga595:
292
+ title: Signal In - Sleep before trying again
293
+ type: await
294
+ topic: ${app}.sleep.execute
295
+ input:
296
+ schema:
297
+ type: object
298
+ properties:
299
+ duration:
300
+ type: number
301
+ index:
302
+ type: number
303
+ workflowId:
304
+ type: string
305
+ parentWorkflowId:
306
+ type: string
307
+ maps:
308
+ duration: '{sigw1.output.data.duration}'
309
+ index: '{sigw1.output.data.index}'
310
+ parentWorkflowId:
311
+ '@pipe':
312
+ - ['{$job.metadata.jid}', '-s']
313
+ - ['{@string.concat}']
314
+ workflowId:
315
+ '@pipe':
316
+ - ['{$job.metadata.jid}', '-$sleep', '{sig.output.metadata.dad}', '-', '{sigw1.output.data.index}']
317
+ - ['{@string.concat}']
318
+ output:
319
+ schema:
320
+ type: object
321
+ properties:
322
+ done:
323
+ type: boolean
324
+ maps:
325
+ done: '{sigw1.output.data.done}'
326
+
327
+ sigc595:
328
+ title: Signal In - Goto Activity siga1
329
+ type: cycle
330
+ ancestor: siga1
331
+ input:
332
+ maps:
333
+ duration: '{siga1.output.data.duration}'
334
+
335
+ siga599:
336
+ title: Signal In - Sleep exponentially longer and retry
337
+ type: hook
338
+ sleep: '{siga1.output.data.duration}'
339
+
340
+ sigc599:
341
+ title: Signal In - Goto Activity siga1
342
+ type: cycle
343
+ ancestor: siga1
344
+ input:
345
+ maps:
346
+ duration:
347
+ '@pipe':
348
+ - ['{siga1.output.data.duration}', '{t1.output.data.backoffCoefficient}']
349
+ - ['{@math.multiply}']
146
350
 
147
351
  a594:
148
352
  title: Wait for signals
@@ -375,7 +579,7 @@ const getWorkflowYAML = (app, version) => {
375
579
  done: true
376
580
 
377
581
  s4:
378
- title: Awaken child FLOWS so they end and self-clean
582
+ title: Awaken child flows so they end and self-clean
379
583
  type: signal
380
584
  subtype: all
381
585
  key_name: parentWorkflowId
@@ -410,6 +614,19 @@ const getWorkflowYAML = (app, version) => {
410
614
  type: boolean
411
615
  maps:
412
616
  done: true
617
+ s5:
618
+ title: Close Signal In Channel
619
+ type: signal
620
+ subtype: one
621
+ topic: ${app}.flow.signal
622
+ signal:
623
+ schema:
624
+ type: object
625
+ properties:
626
+ id:
627
+ type: string
628
+ maps:
629
+ id: '{$job.metadata.jid}'
413
630
 
414
631
  transitions:
415
632
  t1:
@@ -422,6 +639,33 @@ const getWorkflowYAML = (app, version) => {
422
639
  '@pipe':
423
640
  - ['{$job.metadata.key}', true, false]
424
641
  - ['{@conditional.ternary}']
642
+ - to: sig
643
+ sig:
644
+ - to: siga1
645
+ conditions:
646
+ code: 202
647
+ siga1:
648
+ - to: sigw1
649
+ sigw1:
650
+ - to: siga594
651
+ conditions:
652
+ code: 594
653
+ - to: siga595
654
+ conditions:
655
+ code: 595
656
+ - to: siga599
657
+ conditions:
658
+ code: 599
659
+ siga594:
660
+ - to: sigc594
661
+ conditions:
662
+ code: 202
663
+ siga595:
664
+ - to: sigc595
665
+ conditions:
666
+ code: 202
667
+ siga599:
668
+ - to: sigc599
425
669
  a1:
426
670
  - to: w1
427
671
  w1:
@@ -434,16 +678,19 @@ const getWorkflowYAML = (app, version) => {
434
678
  - to: a599
435
679
  conditions:
436
680
  code: 599
681
+ - to: s3
682
+ conditions:
683
+ code: [200, 598, 597, 596]
437
684
  - to: s1
438
685
  conditions:
439
686
  code: [200, 598, 597, 596]
440
687
  - to: s2
441
688
  conditions:
442
689
  code: [200, 598, 597, 596]
443
- - to: s3
690
+ - to: s4
444
691
  conditions:
445
692
  code: [200, 598, 597, 596]
446
- - to: s4
693
+ - to: s5
447
694
  conditions:
448
695
  code: [200, 598, 597, 596]
449
696
  a594:
@@ -464,7 +711,14 @@ const getWorkflowYAML = (app, version) => {
464
711
  match:
465
712
  - expected: '{t1.output.data.workflowId}'
466
713
  actual: '{$self.hook.data.id}'
467
-
714
+
715
+ ${app}.flow.signal:
716
+ - to: sig
717
+ conditions:
718
+ match:
719
+ - expected: '{t1.output.data.workflowId}'
720
+ actual: '{$self.hook.data.id}'
721
+
468
722
  - subscribes: ${app}.activity.execute
469
723
  publishes: ${app}.activity.executed
470
724
 
@@ -495,6 +749,7 @@ const getWorkflowYAML = (app, version) => {
495
749
 
496
750
  activities:
497
751
  t1a:
752
+ title: Activity Flow Trigger
498
753
  type: trigger
499
754
  stats:
500
755
  id: '{$self.input.data.workflowId}'
@@ -505,6 +760,7 @@ const getWorkflowYAML = (app, version) => {
505
760
  target: '{$self.input.data.parentWorkflowId}'
506
761
 
507
762
  w1a:
763
+ title: Activity Worker - Calls Activity Functions
508
764
  type: worker
509
765
  topic: '{t1a.output.data.workflowTopic}'
510
766
  emit: true
@@ -540,8 +796,8 @@ const getWorkflowYAML = (app, version) => {
540
796
  done: true
541
797
 
542
798
  s1a:
799
+ title: Awaken activity flows so they end and self-clean
543
800
  type: hook
544
- title: Wait for cleanup signal
545
801
  hook:
546
802
  type: object
547
803
  properties:
@@ -560,7 +816,6 @@ const getWorkflowYAML = (app, version) => {
560
816
  hooks:
561
817
  ${app}.activity.awaken:
562
818
  - to: s1a
563
- keep_alive: true
564
819
  conditions:
565
820
  match:
566
821
  - expected: '{t1a.output.data.workflowId}'
@@ -597,6 +852,7 @@ const getWorkflowYAML = (app, version) => {
597
852
 
598
853
  activities:
599
854
  t1s:
855
+ title: Sleep Flow Trigger
600
856
  type: trigger
601
857
  stats:
602
858
  id: '{$self.input.data.workflowId}'
@@ -607,14 +863,14 @@ const getWorkflowYAML = (app, version) => {
607
863
  target: '{$self.input.data.parentWorkflowId}'
608
864
 
609
865
  a1s:
610
- type: hook
611
866
  title: Sleep for a duration
867
+ type: hook
612
868
  sleep: '{t1s.output.data.duration}'
613
869
  emit: true
614
870
 
615
871
  a2s:
872
+ title: Awaken sleep flows so they end and self-clean
616
873
  type: hook
617
- title: Wait for cleanup signal
618
874
  hook:
619
875
  type: object
620
876
  properties:
@@ -684,7 +940,7 @@ const getWorkflowYAML = (app, version) => {
684
940
  id: '{$self.input.data.cycleWorkflowId}'
685
941
 
686
942
  a1wc:
687
- title: Split signal data
943
+ title: Pivot - All Cycling Descendants Point Here
688
944
  type: hook
689
945
  cycle: true
690
946
  output:
@@ -723,6 +979,7 @@ const getWorkflowYAML = (app, version) => {
723
979
  - ['{t1wc.output.data.signals}', 1]
724
980
  - ['{@array.slice}']
725
981
  a2wc:
982
+ title: Precalculate targetLength
726
983
  type: hook
727
984
  output:
728
985
  schema:
@@ -734,7 +991,7 @@ const getWorkflowYAML = (app, version) => {
734
991
  targetLength: '{a1wc.output.data.targetLength}'
735
992
 
736
993
  c1wc:
737
- title: Goto Activity a1wc
994
+ title: Goto Activity a1wc - Spawn Signal children
738
995
  type: cycle
739
996
  ancestor: a1wc
740
997
  input:
@@ -840,6 +1097,7 @@ const getWorkflowYAML = (app, version) => {
840
1097
 
841
1098
  activities:
842
1099
  t1ww:
1100
+ title: WFS - Wait For Signal Trigger
843
1101
  type: trigger
844
1102
  stats:
845
1103
  id: '{$self.input.data.workflowId}'
@@ -850,8 +1108,8 @@ const getWorkflowYAML = (app, version) => {
850
1108
  target: '{$self.input.data.parentWorkflowId}'
851
1109
 
852
1110
  a1ww:
1111
+ title: WFS - signal entry point
853
1112
  type: hook
854
- title: Wait for custom signal
855
1113
  emit: true
856
1114
  hook:
857
1115
  type: object
@@ -865,8 +1123,8 @@ const getWorkflowYAML = (app, version) => {
865
1123
  signalId: '{t1ww.output.data.signalId}'
866
1124
 
867
1125
  a2ww:
1126
+ title: WFS - cleanup signal entry point
868
1127
  type: hook
869
- title: Wait for cleanup signal
870
1128
  hook:
871
1129
  type: object
872
1130
  properties:
@@ -903,33 +1161,5 @@ const APP_VERSION = '1';
903
1161
  exports.APP_VERSION = APP_VERSION;
904
1162
  const APP_ID = 'durable';
905
1163
  exports.APP_ID = APP_ID;
906
- const ACTIVITY_SUBSCRIBES_TOPIC = 'durable.activity.execute';
907
- exports.ACTIVITY_SUBSCRIBES_TOPIC = ACTIVITY_SUBSCRIBES_TOPIC;
908
- const ACTIVITY_PUBLISHES_TOPIC = 'durable.activity.executed';
909
- exports.ACTIVITY_PUBLISHES_TOPIC = ACTIVITY_PUBLISHES_TOPIC;
910
- const SLEEP_SUBSCRIBES_TOPIC = 'durable.sleep.execute';
911
- exports.SLEEP_SUBSCRIBES_TOPIC = SLEEP_SUBSCRIBES_TOPIC;
912
- const SLEEP_PUBLISHES_TOPIC = 'durable.sleep.executed';
913
- exports.SLEEP_PUBLISHES_TOPIC = SLEEP_PUBLISHES_TOPIC;
914
- const WFS_SUBSCRIBES_TOPIC = 'durable.wfs.execute';
915
- exports.WFS_SUBSCRIBES_TOPIC = WFS_SUBSCRIBES_TOPIC;
916
- const WFS_PUBLISHES_TOPIC = 'durable.wfs.executed';
917
- exports.WFS_PUBLISHES_TOPIC = WFS_PUBLISHES_TOPIC;
918
- const WFSC_SUBSCRIBES_TOPIC = 'durable.wfsc.execute';
919
- exports.WFSC_SUBSCRIBES_TOPIC = WFSC_SUBSCRIBES_TOPIC;
920
- const WFSC_PUBLISHES_TOPIC = 'durable.wfsc.executed';
921
- exports.WFSC_PUBLISHES_TOPIC = WFSC_PUBLISHES_TOPIC;
922
- const SUBSCRIBES_TOPIC = 'durable.execute';
923
- exports.SUBSCRIBES_TOPIC = SUBSCRIBES_TOPIC;
924
- const PUBLISHES_TOPIC = 'durable.executed';
925
- exports.PUBLISHES_TOPIC = PUBLISHES_TOPIC;
926
- const HOOK_ID = 'durable.awaken';
927
- exports.HOOK_ID = HOOK_ID;
928
- const ACTIVITY_HOOK_ID = 'durable.activity.awaken';
929
- exports.ACTIVITY_HOOK_ID = ACTIVITY_HOOK_ID;
930
- const SLEEP_HOOK_ID = 'durable.sleep.awaken';
931
- exports.SLEEP_HOOK_ID = SLEEP_HOOK_ID;
932
- const WFS_HOOK_ID = 'durable.wfs.awaken';
933
- exports.WFS_HOOK_ID = WFS_HOOK_ID;
934
1164
  const DEFAULT_COEFFICIENT = 10;
935
1165
  exports.DEFAULT_COEFFICIENT = DEFAULT_COEFFICIENT;
@@ -5,5 +5,5 @@ export declare class WorkflowHandleService {
5
5
  workflowId: string;
6
6
  constructor(hotMesh: HotMesh, workflowTopic: string, workflowId: string);
7
7
  signal(signalId: string, data: Record<any, any>): Promise<void>;
8
- result(): Promise<any>;
8
+ result(loadState?: boolean): Promise<any>;
9
9
  }
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WorkflowHandleService = void 0;
4
- const factory_1 = require("./factory");
5
4
  class WorkflowHandleService {
6
5
  constructor(hotMesh, workflowTopic, workflowId) {
7
6
  this.workflowTopic = workflowTopic;
@@ -9,11 +8,25 @@ class WorkflowHandleService {
9
8
  this.hotMesh = hotMesh;
10
9
  }
11
10
  async signal(signalId, data) {
12
- await this.hotMesh.hook('durable.wfs.signal', { id: signalId, data });
11
+ await this.hotMesh.hook(`${this.hotMesh.appId}.wfs.signal`, { id: signalId, data });
13
12
  }
14
- async result() {
13
+ async result(loadState) {
14
+ if (loadState) {
15
+ const state = await this.hotMesh.getState(`${this.hotMesh.appId}.execute`, this.workflowId);
16
+ if (!state.data && state.metadata.err) {
17
+ throw new Error(JSON.parse(state.metadata.err));
18
+ }
19
+ if (state?.data?.done) {
20
+ //child flows are never technically 'done' as they have an open hook
21
+ //that is tied to the parent flow's completion. so, we need to check
22
+ //the 'done' flag on the child flow's payload (not the 'js' metadata field
23
+ //which is typically used); the loadState parameter ensures this
24
+ //check happens early
25
+ return state.data.response;
26
+ }
27
+ }
15
28
  let status = await this.hotMesh.getStatus(this.workflowId);
16
- const topic = `${factory_1.PUBLISHES_TOPIC}.${this.workflowId}`;
29
+ const topic = `${this.hotMesh.appId}.executed.${this.workflowId}`;
17
30
  return new Promise((resolve, reject) => {
18
31
  let isResolved = false;
19
32
  //common fulfill/unsubscribe
@@ -26,7 +39,7 @@ class WorkflowHandleService {
26
39
  return reject(JSON.parse(err));
27
40
  }
28
41
  else if (!response) {
29
- const state = await this.hotMesh.getState(this.workflowTopic, this.workflowId);
42
+ const state = await this.hotMesh.getState(`${this.hotMesh.appId}.execute`, this.workflowId);
30
43
  if (!state.data && state.metadata.err) {
31
44
  return reject(JSON.parse(state.metadata.err));
32
45
  }
@@ -3,10 +3,17 @@ import { RedisClient, RedisMulti } from '../../types/redis';
3
3
  import { StoreService } from '../store';
4
4
  export declare class Search {
5
5
  jobId: string;
6
+ searchSessionId: string;
7
+ searchSessionIndex: number;
6
8
  hotMeshClient: HotMesh;
7
9
  store: StoreService<RedisClient, RedisMulti> | null;
8
10
  safeKey(key: string): string;
9
- constructor(workflowId: string, hotMeshClient: HotMesh);
11
+ constructor(workflowId: string, hotMeshClient: HotMesh, searchSessionId: string);
12
+ /**
13
+ * increments the index to return a unique search session guid when
14
+ * calling any method that produces side effects (changes the value)
15
+ */
16
+ getSearchSessionGuid(): string;
10
17
  set(key: string, value: string): Promise<void>;
11
18
  get(key: string): Promise<string>;
12
19
  del(key: string): Promise<void>;
@@ -8,18 +8,32 @@ class Search {
8
8
  //so its design never conflicts with the hotmesh keyspace
9
9
  return `_${key}`;
10
10
  }
11
- constructor(workflowId, hotMeshClient) {
11
+ constructor(workflowId, hotMeshClient, searchSessionId) {
12
+ this.searchSessionIndex = 0;
12
13
  const keyParams = {
13
14
  appId: hotMeshClient.appId,
14
- jobId: ''
15
+ jobId: workflowId
15
16
  };
16
- const hotMeshPrefix = key_1.KeyService.mintKey(hotMeshClient.namespace, key_1.KeyType.JOB_STATE, keyParams);
17
- this.jobId = `${hotMeshPrefix}${workflowId}`;
17
+ this.jobId = key_1.KeyService.mintKey(hotMeshClient.namespace, key_1.KeyType.JOB_STATE, keyParams);
18
+ this.searchSessionId = searchSessionId;
18
19
  this.hotMeshClient = hotMeshClient;
19
20
  this.store = hotMeshClient.engine.store;
20
21
  }
22
+ /**
23
+ * increments the index to return a unique search session guid when
24
+ * calling any method that produces side effects (changes the value)
25
+ */
26
+ getSearchSessionGuid() {
27
+ //return the search session as it would exist in the search session index
28
+ return `${this.searchSessionId}-${this.searchSessionIndex++}-`;
29
+ }
21
30
  async set(key, value) {
22
- await this.store.exec('HSET', this.jobId, this.safeKey(key), value.toString());
31
+ const ssGuid = this.getSearchSessionGuid();
32
+ const ssGuidValue = Number(await this.store.exec('HINCRBYFLOAT', this.jobId, ssGuid, '1'));
33
+ if (ssGuidValue === 1) {
34
+ //only allowed to set a value the first time
35
+ await this.store.exec('HSET', this.jobId, this.safeKey(key), value.toString());
36
+ }
23
37
  }
24
38
  async get(key) {
25
39
  try {
@@ -31,15 +45,27 @@ class Search {
31
45
  }
32
46
  }
33
47
  async del(key) {
34
- await this.store.exec('HDEL', this.jobId, this.safeKey(key));
48
+ const ssGuid = this.getSearchSessionGuid();
49
+ const ssGuidValue = Number(await this.store.exec('HINCRBYFLOAT', this.jobId, ssGuid, '1'));
50
+ if (ssGuidValue === 1) {
51
+ await this.store.exec('HDEL', this.jobId, this.safeKey(key));
52
+ }
35
53
  }
36
54
  async incr(key, val) {
37
- return Number(await this.store.exec('HINCRBYFLOAT', this.jobId, this.safeKey(key), val.toString()));
55
+ const ssGuid = this.getSearchSessionGuid();
56
+ const ssGuidValue = Number(await this.store.exec('HINCRBYFLOAT', this.jobId, ssGuid, '1'));
57
+ if (ssGuidValue === 1) {
58
+ return Number(await this.store.exec('HINCRBYFLOAT', this.jobId, this.safeKey(key), val.toString()));
59
+ }
38
60
  }
39
61
  async mult(key, val) {
40
- const log = Math.log(val);
41
- const logTotal = Number(await this.store.exec('HINCRBYFLOAT', this.jobId, this.safeKey(key), log.toString()));
42
- return Math.exp(logTotal);
62
+ const ssGuid = this.getSearchSessionGuid();
63
+ const ssGuidValue = Number(await this.store.exec('HINCRBYFLOAT', this.jobId, ssGuid, '1'));
64
+ if (ssGuidValue === 1) {
65
+ const log = Math.log(val);
66
+ const logTotal = Number(await this.store.exec('HINCRBYFLOAT', this.jobId, this.safeKey(key), log.toString()));
67
+ return Math.exp(logTotal);
68
+ }
43
69
  }
44
70
  }
45
71
  exports.Search = Search;
@@ -1,22 +1,20 @@
1
1
  import { HotMeshService as HotMesh } from '../hotmesh';
2
- import { Connection, Registry, WorkerConfig, WorkerOptions, WorkflowSearchOptions } from "../../types/durable";
2
+ import { Connection, Registry, WorkerConfig, WorkerOptions, WorkflowSearchOptions } from '../../types/durable';
3
3
  export declare class WorkerService {
4
4
  static activityRegistry: Registry;
5
5
  static connection: Connection;
6
6
  static instances: Map<string, HotMesh | Promise<HotMesh>>;
7
7
  workflowRunner: HotMesh;
8
8
  activityRunner: HotMesh;
9
- static getHotMesh: (worflowTopic: string, options?: WorkerOptions) => Promise<HotMesh>;
9
+ static getHotMesh: (workflowTopic: string, config?: Partial<WorkerConfig>, options?: WorkerOptions) => Promise<HotMesh>;
10
10
  static activateWorkflow(hotMesh: HotMesh): Promise<void>;
11
- /**
12
- * NOTE: Because the worker imports the workflows dynamically AFTER
13
- * the activities are loaded, there will be items in the registry,
14
- * allowing proxyActivities to succeed.
15
- */
16
11
  static registerActivities<ACT>(activities: ACT): Registry;
17
12
  /**
18
13
  * For those deployments with a redis stack backend (with the FT module),
19
- * this method will configure the search index for the workflow.
14
+ * this method will configure the search index for the workflow. For all
15
+ * others, this method will fail gracefully. In all cases, the values
16
+ * will be stored in the workflow's central HASH data structure, allowing
17
+ * for manual traversal and inspection as well.
20
18
  */
21
19
  static configureSearchIndex(hotMeshClient: HotMesh, search?: WorkflowSearchOptions): Promise<void>;
22
20
  static create(config: WorkerConfig): Promise<WorkerService>;
@@ -31,6 +29,6 @@ export declare class WorkerService {
31
29
  workflowTopic: string;
32
30
  };
33
31
  };
34
- wrapWorkflowFunction(workflowFunction: Function, workflowTopic: string): Function;
32
+ wrapWorkflowFunction(workflowFunction: Function, workflowTopic: string, config: WorkerConfig): Function;
35
33
  static shutdown(): Promise<void>;
36
34
  }