@hotmeshio/hotmesh 0.0.34 → 0.0.35

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 (91) hide show
  1. package/README.md +30 -18
  2. package/build/modules/enums.d.ts +22 -0
  3. package/build/modules/enums.js +29 -0
  4. package/build/modules/errors.d.ts +10 -2
  5. package/build/modules/errors.js +14 -3
  6. package/build/modules/key.d.ts +16 -15
  7. package/build/modules/key.js +18 -15
  8. package/build/modules/utils.d.ts +1 -0
  9. package/build/modules/utils.js +6 -1
  10. package/build/package.json +3 -1
  11. package/build/services/activities/activity.d.ts +5 -0
  12. package/build/services/activities/activity.js +27 -6
  13. package/build/services/activities/await.js +11 -3
  14. package/build/services/activities/cycle.js +10 -2
  15. package/build/services/activities/hook.js +8 -2
  16. package/build/services/activities/index.d.ts +2 -2
  17. package/build/services/activities/index.js +2 -2
  18. package/build/services/activities/interrupt.d.ts +16 -0
  19. package/build/services/activities/interrupt.js +129 -0
  20. package/build/services/activities/signal.js +9 -2
  21. package/build/services/activities/trigger.d.ts +4 -0
  22. package/build/services/activities/trigger.js +14 -4
  23. package/build/services/activities/worker.js +10 -2
  24. package/build/services/collator/index.d.ts +4 -0
  25. package/build/services/collator/index.js +8 -0
  26. package/build/services/compiler/deployer.js +1 -3
  27. package/build/services/connector/index.js +2 -3
  28. package/build/services/durable/client.js +7 -3
  29. package/build/services/durable/factory.js +65 -284
  30. package/build/services/durable/handle.d.ts +37 -0
  31. package/build/services/durable/handle.js +52 -9
  32. package/build/services/durable/meshos.js +2 -2
  33. package/build/services/durable/worker.js +9 -2
  34. package/build/services/durable/workflow.d.ts +24 -0
  35. package/build/services/durable/workflow.js +56 -1
  36. package/build/services/engine/index.d.ts +14 -6
  37. package/build/services/engine/index.js +52 -27
  38. package/build/services/hotmesh/index.d.ts +3 -1
  39. package/build/services/hotmesh/index.js +11 -3
  40. package/build/services/quorum/index.d.ts +1 -0
  41. package/build/services/quorum/index.js +10 -0
  42. package/build/services/signaler/stream.js +25 -29
  43. package/build/services/store/index.d.ts +40 -4
  44. package/build/services/store/index.js +114 -9
  45. package/build/services/task/index.d.ts +5 -4
  46. package/build/services/task/index.js +12 -14
  47. package/build/types/activity.d.ts +35 -5
  48. package/build/types/durable.d.ts +4 -0
  49. package/build/types/index.d.ts +1 -1
  50. package/build/types/job.d.ts +18 -1
  51. package/build/types/quorum.d.ts +11 -7
  52. package/build/types/stream.d.ts +4 -1
  53. package/build/types/stream.js +2 -0
  54. package/modules/enums.ts +32 -0
  55. package/modules/errors.ts +24 -9
  56. package/modules/key.ts +4 -1
  57. package/modules/utils.ts +5 -0
  58. package/package.json +3 -1
  59. package/services/activities/activity.ts +34 -8
  60. package/services/activities/await.ts +11 -4
  61. package/services/activities/cycle.ts +10 -3
  62. package/services/activities/hook.ts +8 -3
  63. package/services/activities/index.ts +2 -2
  64. package/services/activities/interrupt.ts +159 -0
  65. package/services/activities/signal.ts +9 -3
  66. package/services/activities/trigger.ts +21 -5
  67. package/services/activities/worker.ts +10 -3
  68. package/services/collator/index.ts +10 -1
  69. package/services/compiler/deployer.ts +1 -3
  70. package/services/connector/index.ts +3 -5
  71. package/services/durable/client.ts +8 -4
  72. package/services/durable/factory.ts +65 -284
  73. package/services/durable/handle.ts +55 -9
  74. package/services/durable/meshos.ts +2 -3
  75. package/services/durable/worker.ts +9 -2
  76. package/services/durable/workflow.ts +66 -2
  77. package/services/engine/index.ts +74 -26
  78. package/services/hotmesh/index.ts +14 -4
  79. package/services/quorum/index.ts +9 -0
  80. package/services/signaler/stream.ts +27 -24
  81. package/services/store/index.ts +119 -11
  82. package/services/task/index.ts +18 -18
  83. package/types/activity.ts +38 -8
  84. package/types/durable.ts +8 -4
  85. package/types/index.ts +1 -1
  86. package/types/job.ts +30 -1
  87. package/types/quorum.ts +13 -8
  88. package/types/stream.ts +3 -0
  89. package/build/services/activities/iterate.d.ts +0 -9
  90. package/build/services/activities/iterate.js +0 -13
  91. package/services/activities/iterate.ts +0 -26
@@ -1,6 +1,5 @@
1
- import { nanoid } from 'nanoid';
2
1
  import { DuplicateJobError } from '../../modules/errors';
3
- import { formatISODate, getTimeSeries } from '../../modules/utils';
2
+ import { formatISODate, getTimeSeries, guid } from '../../modules/utils';
4
3
  import { Activity } from './activity';
5
4
  import { CollatorService } from '../collator';
6
5
  import { EngineService } from '../engine';
@@ -47,6 +46,7 @@ class Trigger extends Activity {
47
46
  const multi = this.store.getMulti();
48
47
  await this.setState(multi);
49
48
  await this.setStats(multi);
49
+ await this.setDependency(multi);
50
50
  await multi.exec();
51
51
 
52
52
  telemetry.mapActivityAttributes();
@@ -68,8 +68,8 @@ class Trigger extends Activity {
68
68
  telemetry.setActivityError(error.message);
69
69
  throw error;
70
70
  } finally {
71
- telemetry.endJobSpan();
72
- telemetry.endActivitySpan();
71
+ telemetry?.endJobSpan();
72
+ telemetry?.endActivitySpan();
73
73
  this.logger.debug('trigger-process-end', { subscribes: this.config.subscribes, jid: this.context.metadata.jid });
74
74
  }
75
75
  }
@@ -161,7 +161,7 @@ class Trigger extends Activity {
161
161
 
162
162
  resolveJobId(context: Partial<JobState>): string {
163
163
  const jobId = this.config.stats?.id;
164
- return jobId ? Pipe.resolve(jobId, context) : nanoid();
164
+ return jobId ? Pipe.resolve(jobId, context) : guid();
165
165
  }
166
166
 
167
167
  resolveJobKey(context: Partial<JobState>): string {
@@ -176,6 +176,22 @@ class Trigger extends Activity {
176
176
  }
177
177
  }
178
178
 
179
+ /**
180
+ * Registers this job as a dependent of the parent job
181
+ */
182
+ async setDependency(multi?: RedisMulti): Promise<void> {
183
+ const depKey = this.config.stats?.parent;
184
+ const resolvedDepKey = depKey ? Pipe.resolve(depKey, this.context) : '';
185
+ if (resolvedDepKey) {
186
+ await this.store.setDependency(
187
+ resolvedDepKey,
188
+ this.context.metadata.tpc,
189
+ this.context.metadata.jid,
190
+ multi,
191
+ );
192
+ }
193
+ }
194
+
179
195
  async setStats(multi?: RedisMulti): Promise<void> {
180
196
  const md = this.context.metadata;
181
197
  if (md.key && this.config.stats?.measures) {
@@ -1,4 +1,4 @@
1
- import { GetStateError } from '../../modules/errors';
1
+ import { GetStateError, InactiveJobError } from '../../modules/errors';
2
2
  import { Activity } from './activity';
3
3
  import { CollatorService } from '../collator';
4
4
  import { EngineService } from '../engine';
@@ -12,6 +12,7 @@ import { MultiResponseFlags, RedisMulti } from '../../types/redis';
12
12
  import { StreamData} from '../../types/stream';
13
13
  import { TelemetryService } from '../telemetry';
14
14
  import { Pipe } from '../pipe';
15
+ import { guid } from '../../modules/utils';
15
16
 
16
17
  class Worker extends Activity {
17
18
  config: WorkerActivity;
@@ -35,6 +36,7 @@ class Worker extends Activity {
35
36
  this.setLeg(1);
36
37
  await CollatorService.notarizeEntry(this);
37
38
  await this.getState();
39
+ CollatorService.assertJobActive(this.context.metadata.js, this.context.metadata.jid, this.metadata.aid);
38
40
  telemetry = new TelemetryService(this.engine.appId, this.config, this.metadata, this.context);
39
41
  telemetry.startActivitySpan(this.leg);
40
42
  this.mapInputData();
@@ -58,15 +60,19 @@ class Worker extends Activity {
58
60
 
59
61
  return this.context.metadata.aid;
60
62
  } catch (error) {
61
- if (error instanceof GetStateError) {
63
+ if (error instanceof InactiveJobError) {
64
+ this.logger.error('await-inactive-job-error', { error });
65
+ return;
66
+ } else if (error instanceof GetStateError) {
62
67
  this.logger.error('worker-get-state-error', { error });
68
+ return;
63
69
  } else {
64
70
  this.logger.error('worker-process-error', { error });
65
71
  }
66
72
  telemetry.setActivityError(error.message);
67
73
  throw error;
68
74
  } finally {
69
- telemetry.endActivitySpan();
75
+ telemetry?.endActivitySpan();
70
76
  this.logger.debug('worker-process-end', { jid: this.context.metadata.jid, aid: this.metadata.aid });
71
77
  }
72
78
  }
@@ -75,6 +81,7 @@ class Worker extends Activity {
75
81
  const topic = Pipe.resolve(this.config.subtype, this.context);
76
82
  const streamData: StreamData = {
77
83
  metadata: {
84
+ guid: guid(),
78
85
  jid: this.context.metadata.jid,
79
86
  dad: this.metadata.dad,
80
87
  aid: this.metadata.aid,
@@ -1,4 +1,4 @@
1
- import { CollationError } from '../../modules/errors';
1
+ import { CollationError, InactiveJobError } from '../../modules/errors';
2
2
  import { RedisMulti } from '../../types/redis';
3
3
  import { CollationFaultType, CollationStage } from '../../types/collator';
4
4
  import { ActivityDuplex } from '../../types/activity';
@@ -11,6 +11,15 @@ class CollatorService {
11
11
  //max int digit count that supports `hincrby`
12
12
  static targetLength = 15;
13
13
 
14
+ /**
15
+ * Upon re/entry, verify that the job status is active
16
+ */
17
+ static assertJobActive(status: number, jobId: string, activityId: string): void {
18
+ if (status <= 0) {
19
+ throw new InactiveJobError(jobId, status, activityId);
20
+ }
21
+ }
22
+
14
23
  /**
15
24
  * returns the dimensional address (dad) for the target; due
16
25
  * to the nature of the notary system, the dad for leg 2 entry
@@ -143,9 +143,7 @@ class Deployer {
143
143
  if (graph.publishes) {
144
144
  activities[activityKey].publishes = graph.publishes;
145
145
  }
146
- if (graph.expire) {
147
- activities[activityKey].expire = graph.expire;
148
- }
146
+ activities[activityKey].expire = graph.expire ?? undefined;
149
147
  }
150
148
  }
151
149
  }
@@ -1,6 +1,4 @@
1
- import { nanoid } from 'nanoid';
2
-
3
- import { identifyRedisTypeFromClass } from '../../modules/utils';
1
+ import { guid, identifyRedisTypeFromClass } from '../../modules/utils';
4
2
  import { RedisConnection as IORedisConnection } from '../connector/clients/ioredis';
5
3
  import { RedisConnection } from '../connector/clients/redis';
6
4
  import {
@@ -23,14 +21,14 @@ export class ConnectorService {
23
21
  if (identifyRedisTypeFromClass(Redis) === 'redis') {
24
22
  for (let i = 1; i <= 3; i++) {
25
23
  instances.push(RedisConnection.connect(
26
- nanoid(),
24
+ guid(),
27
25
  Redis as RedisClassType,
28
26
  options as RedisClientOptions));
29
27
  }
30
28
  } else {
31
29
  for (let i = 1; i <= 3; i++) {
32
30
  instances.push(IORedisConnection.connect(
33
- nanoid(),
31
+ guid(),
34
32
  Redis as IORedisClassType,
35
33
  options as IORedisClientOptions));
36
34
  }
@@ -11,6 +11,7 @@ import { JobState } from '../../types/job';
11
11
  import { KeyService, KeyType } from '../../modules/key';
12
12
  import { Search } from './search';
13
13
  import { StreamStatus } from '../../types';
14
+ import { DURABLE_EXPIRE_SECONDS } from '../../modules/enums';
14
15
 
15
16
  export class ClientService {
16
17
 
@@ -96,12 +97,15 @@ export class ClientService {
96
97
  const workflowName = options.entity ?? options.workflowName;
97
98
  const trc = options.workflowTrace;
98
99
  const spn = options.workflowSpan;
99
- //topic is concat of taskQueue and workflowName
100
+ //NOTE: HotMesh 'workflowTopic' is a created by concatenating
101
+ // the taskQueue and workflowName used by the Durable module
100
102
  const workflowTopic = `${taskQueueName}-${workflowName}`;
101
103
  const hotMeshClient = await this.getHotMeshClient(workflowTopic, options.namespace);
102
- this.configureSearchIndex(hotMeshClient, options.search)
104
+ this.configureSearchIndex(hotMeshClient, options.search);
103
105
  const payload = {
104
106
  arguments: [...options.args],
107
+ originJobId: options.originJobId,
108
+ expire: options.expire ?? DURABLE_EXPIRE_SECONDS,
105
109
  parentWorkflowId: options.parentWorkflowId,
106
110
  workflowId: options.workflowId || HotMesh.guid(),
107
111
  workflowTopic: workflowTopic,
@@ -113,12 +117,12 @@ export class ClientService {
113
117
  payload,
114
118
  context as JobState
115
119
  );
116
- // Seed search data if present
120
+ // Seed search data
117
121
  if (jobId && options.search?.data) {
118
122
  const searchSessionId = `-search-0`;
119
123
  const search = new Search(jobId, hotMeshClient, searchSessionId);
120
124
  const entries = Object.entries(options.search.data).flat();
121
- search.set(...entries);
125
+ await search.set(...entries);
122
126
  }
123
127
  return new WorkflowHandleService(hotMeshClient, workflowTopic, jobId);
124
128
  },