@hotmeshio/hotmesh 0.0.6 → 0.0.7

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.6",
3
+ "version": "0.0.7",
4
4
  "description": "Durable Workflows",
5
5
  "main": "build/cjs/index.js",
6
6
  "module": "build/esm/index.js",
@@ -321,9 +321,8 @@ class Activity {
321
321
  let { dad, jid } = this.context.metadata;
322
322
  jobId = jobId || jid;
323
323
  const dIds = collator_1.CollatorService.getDimensionsById([...this.config.ancestors, this.metadata.aid], dad);
324
- //`state` is a flat hash
324
+ //`state` is a flat hash; context is a tree
325
325
  const [state, status] = await this.store.getState(jobId, consumes, dIds);
326
- //`context` is a tree
327
326
  this.context = (0, utils_1.restoreHierarchy)(state);
328
327
  this.initDimensionalAddress(dad);
329
328
  this.initSelf(this.context);
@@ -2,6 +2,7 @@ import { Activity } from './activity';
2
2
  import { EngineService } from '../engine';
3
3
  import { ActivityData, ActivityMetadata, ActivityType, WorkerActivity } from '../../types/activity';
4
4
  import { JobState } from '../../types/job';
5
+ import { MultiResponseFlags } from '../../types/redis';
5
6
  import { StreamCode, StreamStatus } from '../../types/stream';
6
7
  import { TelemetryService } from '../telemetry';
7
8
  declare class Worker extends Activity {
@@ -13,5 +14,6 @@ declare class Worker extends Activity {
13
14
  processPending(telemetry: TelemetryService): Promise<void>;
14
15
  processSuccess(telemetry: TelemetryService): Promise<void>;
15
16
  processError(telemetry: TelemetryService): Promise<void>;
17
+ transitionAdjacent(multiResponse: MultiResponseFlags, telemetry: TelemetryService): Promise<void>;
16
18
  }
17
19
  export { Worker };
@@ -120,11 +120,9 @@ class Worker extends activity_1.Activity {
120
120
  const multi = this.store.getMulti();
121
121
  await this.setState(multi);
122
122
  await collator_1.CollatorService.notarizeContinuation(this, multi);
123
- await this.setStatus(0, multi);
123
+ await this.setStatus(this.adjacencyList.length, multi);
124
124
  const multiResponse = await multi.exec();
125
- telemetry.mapActivityAttributes();
126
- const jobStatus = this.resolveStatus(multiResponse);
127
- telemetry.setActivityAttributes({ 'app.job.jss': jobStatus });
125
+ this.transitionAdjacent(multiResponse, telemetry);
128
126
  }
129
127
  async processSuccess(telemetry) {
130
128
  this.bindActivityData('output');
@@ -135,14 +133,7 @@ class Worker extends activity_1.Activity {
135
133
  await collator_1.CollatorService.notarizeCompletion(this, multi);
136
134
  await this.setStatus(this.adjacencyList.length - 1, multi);
137
135
  const multiResponse = await multi.exec();
138
- telemetry.mapActivityAttributes();
139
- const jobStatus = this.resolveStatus(multiResponse);
140
- const attrs = { 'app.job.jss': jobStatus };
141
- const messageIds = await this.transition(this.adjacencyList, jobStatus);
142
- if (messageIds.length) {
143
- attrs['app.activity.mids'] = messageIds.join(',');
144
- }
145
- telemetry.setActivityAttributes(attrs);
136
+ this.transitionAdjacent(multiResponse, telemetry);
146
137
  }
147
138
  async processError(telemetry) {
148
139
  this.bindActivityError(this.data);
@@ -152,6 +143,9 @@ class Worker extends activity_1.Activity {
152
143
  await collator_1.CollatorService.notarizeCompletion(this, multi);
153
144
  await this.setStatus(this.adjacencyList.length - 1, multi);
154
145
  const multiResponse = await multi.exec();
146
+ this.transitionAdjacent(multiResponse, telemetry);
147
+ }
148
+ async transitionAdjacent(multiResponse, telemetry) {
155
149
  telemetry.mapActivityAttributes();
156
150
  const jobStatus = this.resolveStatus(multiResponse);
157
151
  const attrs = { 'app.job.jss': jobStatus };
@@ -99,16 +99,20 @@ class WorkerService {
99
99
  * allowing proxyActivities to succeed.
100
100
  */
101
101
  static registerActivities(activities) {
102
- Object.keys(activities).forEach(key => {
103
- WorkerService.activityRegistry[key] = activities[key];
104
- });
102
+ if (typeof activities === 'function') {
103
+ WorkerService.activityRegistry[activities.name] = activities;
104
+ }
105
+ else {
106
+ Object.keys(activities).forEach(key => {
107
+ WorkerService.activityRegistry[activities[key].name] = activities[key];
108
+ });
109
+ }
105
110
  return WorkerService.activityRegistry;
106
111
  }
107
112
  static async create(config) {
113
+ //always call `registerActivities` before `import`
108
114
  WorkerService.connection = config.connection;
109
- //pre-cache user activity functions
110
115
  WorkerService.registerActivities(config.activities);
111
- //import the user's workflow file (triggers activity functions to be wrapped)
112
116
  const workflow = await Promise.resolve(`${config.workflowsPath}`).then(s => __importStar(require(s)));
113
117
  const [workflowFunctionName, workflowFunction] = WorkerService.resolveWorkflowTarget(workflow);
114
118
  const baseTopic = `${config.taskQueue}-${workflowFunctionName}`;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/hotmesh",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Durable Workflows",
5
5
  "main": "build/cjs/index.js",
6
6
  "module": "build/esm/index.js",
@@ -318,9 +318,8 @@ class Activity {
318
318
  let { dad, jid } = this.context.metadata;
319
319
  jobId = jobId || jid;
320
320
  const dIds = CollatorService.getDimensionsById([...this.config.ancestors, this.metadata.aid], dad);
321
- //`state` is a flat hash
321
+ //`state` is a flat hash; context is a tree
322
322
  const [state, status] = await this.store.getState(jobId, consumes, dIds);
323
- //`context` is a tree
324
323
  this.context = restoreHierarchy(state);
325
324
  this.initDimensionalAddress(dad);
326
325
  this.initSelf(this.context);
@@ -2,6 +2,7 @@ import { Activity } from './activity';
2
2
  import { EngineService } from '../engine';
3
3
  import { ActivityData, ActivityMetadata, ActivityType, WorkerActivity } from '../../types/activity';
4
4
  import { JobState } from '../../types/job';
5
+ import { MultiResponseFlags } from '../../types/redis';
5
6
  import { StreamCode, StreamStatus } from '../../types/stream';
6
7
  import { TelemetryService } from '../telemetry';
7
8
  declare class Worker extends Activity {
@@ -13,5 +14,6 @@ declare class Worker extends Activity {
13
14
  processPending(telemetry: TelemetryService): Promise<void>;
14
15
  processSuccess(telemetry: TelemetryService): Promise<void>;
15
16
  processError(telemetry: TelemetryService): Promise<void>;
17
+ transitionAdjacent(multiResponse: MultiResponseFlags, telemetry: TelemetryService): Promise<void>;
16
18
  }
17
19
  export { Worker };
@@ -117,11 +117,9 @@ class Worker extends Activity {
117
117
  const multi = this.store.getMulti();
118
118
  await this.setState(multi);
119
119
  await CollatorService.notarizeContinuation(this, multi);
120
- await this.setStatus(0, multi);
120
+ await this.setStatus(this.adjacencyList.length, multi);
121
121
  const multiResponse = await multi.exec();
122
- telemetry.mapActivityAttributes();
123
- const jobStatus = this.resolveStatus(multiResponse);
124
- telemetry.setActivityAttributes({ 'app.job.jss': jobStatus });
122
+ this.transitionAdjacent(multiResponse, telemetry);
125
123
  }
126
124
  async processSuccess(telemetry) {
127
125
  this.bindActivityData('output');
@@ -132,14 +130,7 @@ class Worker extends Activity {
132
130
  await CollatorService.notarizeCompletion(this, multi);
133
131
  await this.setStatus(this.adjacencyList.length - 1, multi);
134
132
  const multiResponse = await multi.exec();
135
- telemetry.mapActivityAttributes();
136
- const jobStatus = this.resolveStatus(multiResponse);
137
- const attrs = { 'app.job.jss': jobStatus };
138
- const messageIds = await this.transition(this.adjacencyList, jobStatus);
139
- if (messageIds.length) {
140
- attrs['app.activity.mids'] = messageIds.join(',');
141
- }
142
- telemetry.setActivityAttributes(attrs);
133
+ this.transitionAdjacent(multiResponse, telemetry);
143
134
  }
144
135
  async processError(telemetry) {
145
136
  this.bindActivityError(this.data);
@@ -149,6 +140,9 @@ class Worker extends Activity {
149
140
  await CollatorService.notarizeCompletion(this, multi);
150
141
  await this.setStatus(this.adjacencyList.length - 1, multi);
151
142
  const multiResponse = await multi.exec();
143
+ this.transitionAdjacent(multiResponse, telemetry);
144
+ }
145
+ async transitionAdjacent(multiResponse, telemetry) {
152
146
  telemetry.mapActivityAttributes();
153
147
  const jobStatus = this.resolveStatus(multiResponse);
154
148
  const attrs = { 'app.job.jss': jobStatus };
@@ -73,16 +73,20 @@ class WorkerService {
73
73
  * allowing proxyActivities to succeed.
74
74
  */
75
75
  static registerActivities(activities) {
76
- Object.keys(activities).forEach(key => {
77
- WorkerService.activityRegistry[key] = activities[key];
78
- });
76
+ if (typeof activities === 'function') {
77
+ WorkerService.activityRegistry[activities.name] = activities;
78
+ }
79
+ else {
80
+ Object.keys(activities).forEach(key => {
81
+ WorkerService.activityRegistry[activities[key].name] = activities[key];
82
+ });
83
+ }
79
84
  return WorkerService.activityRegistry;
80
85
  }
81
86
  static async create(config) {
87
+ //always call `registerActivities` before `import`
82
88
  WorkerService.connection = config.connection;
83
- //pre-cache user activity functions
84
89
  WorkerService.registerActivities(config.activities);
85
- //import the user's workflow file (triggers activity functions to be wrapped)
86
90
  const workflow = await import(config.workflowsPath);
87
91
  const [workflowFunctionName, workflowFunction] = WorkerService.resolveWorkflowTarget(workflow);
88
92
  const baseTopic = `${config.taskQueue}-${workflowFunctionName}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/hotmesh",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Durable Workflows",
5
5
  "main": "build/cjs/index.js",
6
6
  "module": "build/esm/index.js",
@@ -392,9 +392,8 @@ class Activity {
392
392
  let { dad, jid } = this.context.metadata;
393
393
  jobId = jobId || jid;
394
394
  const dIds = CollatorService.getDimensionsById([...this.config.ancestors, this.metadata.aid], dad);
395
- //`state` is a flat hash
395
+ //`state` is a flat hash; context is a tree
396
396
  const [state, status] = await this.store.getState(jobId, consumes, dIds);
397
- //`context` is a tree
398
397
  this.context = restoreHierarchy(state) as JobState;
399
398
  this.initDimensionalAddress(dad);
400
399
  this.initSelf(this.context);
@@ -110,6 +110,7 @@ class Worker extends Activity {
110
110
 
111
111
  telemetry = new TelemetryService(this.engine.appId, this.config, this.metadata, this.context);
112
112
  let isComplete = CollatorService.isActivityComplete(this.context.metadata.js);
113
+
113
114
  if (isComplete) {
114
115
  this.logger.warn('worker-process-event-duplicate', { jid, aid });
115
116
  this.logger.debug('worker-process-event-duplicate-resolution', { resolution: 'Increase HotMesh config `reclaimDelay` timeout.' });
@@ -141,11 +142,9 @@ class Worker extends Activity {
141
142
  await this.setState(multi);
142
143
  await CollatorService.notarizeContinuation(this, multi);
143
144
 
144
- await this.setStatus(0, multi);
145
+ await this.setStatus(this.adjacencyList.length, multi);
145
146
  const multiResponse = await multi.exec() as MultiResponseFlags;
146
- telemetry.mapActivityAttributes();
147
- const jobStatus = this.resolveStatus(multiResponse);
148
- telemetry.setActivityAttributes({ 'app.job.jss': jobStatus });
147
+ this.transitionAdjacent(multiResponse, telemetry);
149
148
  }
150
149
 
151
150
  async processSuccess(telemetry: TelemetryService): Promise<void> {
@@ -158,14 +157,7 @@ class Worker extends Activity {
158
157
 
159
158
  await this.setStatus(this.adjacencyList.length - 1, multi);
160
159
  const multiResponse = await multi.exec() as MultiResponseFlags;
161
- telemetry.mapActivityAttributes();
162
- const jobStatus = this.resolveStatus(multiResponse);
163
- const attrs: StringScalarType = { 'app.job.jss': jobStatus };
164
- const messageIds = await this.transition(this.adjacencyList, jobStatus);
165
- if (messageIds.length) {
166
- attrs['app.activity.mids'] = messageIds.join(',')
167
- }
168
- telemetry.setActivityAttributes(attrs);
160
+ this.transitionAdjacent(multiResponse, telemetry);
169
161
  }
170
162
 
171
163
  async processError(telemetry: TelemetryService): Promise<void> {
@@ -177,6 +169,10 @@ class Worker extends Activity {
177
169
 
178
170
  await this.setStatus(this.adjacencyList.length - 1, multi);
179
171
  const multiResponse = await multi.exec() as MultiResponseFlags;
172
+ this.transitionAdjacent(multiResponse, telemetry);
173
+ }
174
+
175
+ async transitionAdjacent(multiResponse: MultiResponseFlags, telemetry: TelemetryService): Promise<void> {
180
176
  telemetry.mapActivityAttributes();
181
177
  const jobStatus = this.resolveStatus(multiResponse);
182
178
  const attrs: StringScalarType = { 'app.job.jss': jobStatus };
@@ -92,17 +92,20 @@ export class WorkerService {
92
92
  * allowing proxyActivities to succeed.
93
93
  */
94
94
  static registerActivities<ACT>(activities: ACT): Registry {
95
- Object.keys(activities).forEach(key => {
96
- WorkerService.activityRegistry[key] = (activities as any)[key];
97
- });
95
+ if (typeof activities === 'function') {
96
+ WorkerService.activityRegistry[activities.name] = activities as Function;
97
+ } else {
98
+ Object.keys(activities).forEach(key => {
99
+ WorkerService.activityRegistry[activities[key].name] = (activities as any)[key] as Function;
100
+ });
101
+ }
98
102
  return WorkerService.activityRegistry;
99
103
  }
100
104
 
101
105
  static async create(config: WorkerConfig) {
106
+ //always call `registerActivities` before `import`
102
107
  WorkerService.connection = config.connection;
103
- //pre-cache user activity functions
104
108
  WorkerService.registerActivities<typeof config.activities>(config.activities);
105
- //import the user's workflow file (triggers activity functions to be wrapped)
106
109
  const workflow = await import(config.workflowsPath);
107
110
  const [workflowFunctionName, workflowFunction] = WorkerService.resolveWorkflowTarget(workflow);
108
111
  const baseTopic = `${config.taskQueue}-${workflowFunctionName}`;
@@ -111,7 +114,6 @@ export class WorkerService {
111
114
 
112
115
  //initialize supporting workflows
113
116
  const worker = new WorkerService();
114
-
115
117
  const activityRunner = await worker.initActivityWorkflow(config, activityTopic);
116
118
  await WorkerService.activateWorkflow(activityRunner, activityTopic, getActivityYAML);
117
119
  worker.workflowRunner = await worker.initWorkerWorkflow(config, workflowTopic, workflowFunction);