@hotmeshio/hotmesh 0.0.6 → 0.0.8
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.
- package/build/cjs/package.json +3 -1
- package/build/cjs/services/activities/activity.d.ts +6 -0
- package/build/cjs/services/activities/activity.js +84 -9
- package/build/cjs/services/activities/await.d.ts +2 -2
- package/build/cjs/services/activities/await.js +5 -5
- package/build/cjs/services/activities/cycle.d.ts +19 -0
- package/build/cjs/services/activities/cycle.js +77 -0
- package/build/cjs/services/activities/index.d.ts +4 -2
- package/build/cjs/services/activities/index.js +4 -2
- package/build/cjs/services/activities/worker.d.ts +0 -6
- package/build/cjs/services/activities/worker.js +1 -93
- package/build/cjs/services/collator/index.d.ts +18 -1
- package/build/cjs/services/collator/index.js +41 -11
- package/build/cjs/services/durable/factory.js +17 -1
- package/build/cjs/services/durable/worker.d.ts +1 -0
- package/build/cjs/services/durable/worker.js +18 -19
- package/build/cjs/services/durable/workflow.js +5 -1
- package/build/cjs/services/mapper/index.js +3 -0
- package/build/cjs/services/signaler/stream.js +0 -1
- package/build/cjs/types/activity.d.ts +7 -2
- package/build/cjs/types/index.d.ts +1 -1
- package/build/esm/package.json +3 -1
- package/build/esm/services/activities/activity.d.ts +6 -0
- package/build/esm/services/activities/activity.js +84 -9
- package/build/esm/services/activities/await.d.ts +2 -2
- package/build/esm/services/activities/await.js +5 -5
- package/build/esm/services/activities/cycle.d.ts +19 -0
- package/build/esm/services/activities/cycle.js +74 -0
- package/build/esm/services/activities/index.d.ts +4 -2
- package/build/esm/services/activities/index.js +4 -2
- package/build/esm/services/activities/worker.d.ts +0 -6
- package/build/esm/services/activities/worker.js +1 -93
- package/build/esm/services/collator/index.d.ts +18 -1
- package/build/esm/services/collator/index.js +41 -11
- package/build/esm/services/durable/factory.js +17 -1
- package/build/esm/services/durable/worker.d.ts +1 -0
- package/build/esm/services/durable/worker.js +18 -19
- package/build/esm/services/durable/workflow.js +5 -1
- package/build/esm/services/mapper/index.js +3 -0
- package/build/esm/services/signaler/stream.js +0 -1
- package/build/esm/types/activity.d.ts +7 -2
- package/build/esm/types/index.d.ts +1 -1
- package/package.json +3 -1
- package/services/activities/activity.ts +91 -9
- package/services/activities/await.ts +5 -5
- package/services/activities/cycle.ts +96 -0
- package/services/activities/index.ts +4 -2
- package/services/activities/worker.ts +2 -97
- package/services/collator/index.ts +43 -11
- package/services/durable/factory.ts +17 -1
- package/services/durable/worker.ts +18 -19
- package/services/durable/workflow.ts +4 -1
- package/services/mapper/index.ts +3 -0
- package/services/signaler/stream.ts +0 -1
- package/types/activity.ts +8 -1
- package/types/index.ts +1 -0
|
@@ -43,7 +43,7 @@ class Worker extends Activity {
|
|
|
43
43
|
this.mapInputData();
|
|
44
44
|
|
|
45
45
|
const multi = this.store.getMulti();
|
|
46
|
-
//await this.registerTimeout();
|
|
46
|
+
//todo: await this.registerTimeout();
|
|
47
47
|
await CollatorService.authorizeReentry(this, multi);
|
|
48
48
|
await this.setState(multi);
|
|
49
49
|
await this.setStatus(0, multi);
|
|
@@ -56,13 +56,12 @@ class Worker extends Activity {
|
|
|
56
56
|
'app.activity.mid': messageId,
|
|
57
57
|
'app.job.jss': jobStatus
|
|
58
58
|
});
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
return this.context.metadata.aid;
|
|
61
61
|
} catch (error) {
|
|
62
62
|
if (error instanceof GetStateError) {
|
|
63
63
|
this.logger.error('worker-get-state-error', error);
|
|
64
64
|
} else {
|
|
65
|
-
console.error(error);
|
|
66
65
|
this.logger.error('worker-process-error', error);
|
|
67
66
|
}
|
|
68
67
|
telemetry.setActivityError(error.message);
|
|
@@ -92,100 +91,6 @@ class Worker extends Activity {
|
|
|
92
91
|
}
|
|
93
92
|
return (await this.engine.streamSignaler?.publishMessage(this.config.subtype, streamData)) as string;
|
|
94
93
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
//******** SIGNAL RE-ENTRY POINT (DUPLEX LEG 2 of 2) ********//
|
|
98
|
-
async processEvent(status: StreamStatus = StreamStatus.SUCCESS, code: StreamCode = 200): Promise<void> {
|
|
99
|
-
this.setLeg(2);
|
|
100
|
-
const jid = this.context.metadata.jid;
|
|
101
|
-
const aid = this.metadata.aid;
|
|
102
|
-
this.status = status;
|
|
103
|
-
this.code = code;
|
|
104
|
-
this.logger.debug('worker-process-event', { topic: this.config.subtype, jid, aid, status, code });
|
|
105
|
-
let telemetry: TelemetryService;
|
|
106
|
-
try {
|
|
107
|
-
await this.getState();
|
|
108
|
-
const aState = await CollatorService.notarizeReentry(this);
|
|
109
|
-
this.adjacentIndex = CollatorService.getDimensionalIndex(aState);
|
|
110
|
-
|
|
111
|
-
telemetry = new TelemetryService(this.engine.appId, this.config, this.metadata, this.context);
|
|
112
|
-
let isComplete = CollatorService.isActivityComplete(this.context.metadata.js);
|
|
113
|
-
if (isComplete) {
|
|
114
|
-
this.logger.warn('worker-process-event-duplicate', { jid, aid });
|
|
115
|
-
this.logger.debug('worker-process-event-duplicate-resolution', { resolution: 'Increase HotMesh config `reclaimDelay` timeout.' });
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
telemetry.startActivitySpan(this.leg);
|
|
119
|
-
if (status === StreamStatus.PENDING) {
|
|
120
|
-
await this.processPending(telemetry);
|
|
121
|
-
} else if (status === StreamStatus.SUCCESS) {
|
|
122
|
-
await this.processSuccess(telemetry);
|
|
123
|
-
} else {
|
|
124
|
-
await this.processError(telemetry);
|
|
125
|
-
}
|
|
126
|
-
} catch (error) {
|
|
127
|
-
this.logger.error('worker-process-event-error', error);
|
|
128
|
-
telemetry.setActivityError(error.message);
|
|
129
|
-
throw error;
|
|
130
|
-
} finally {
|
|
131
|
-
telemetry.endActivitySpan();
|
|
132
|
-
this.logger.debug('worker-process-event-end', { jid, aid });
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async processPending(telemetry: TelemetryService): Promise<void> {
|
|
137
|
-
this.bindActivityData('output');
|
|
138
|
-
this.adjacencyList = await this.filterAdjacent();
|
|
139
|
-
this.mapJobData();
|
|
140
|
-
const multi = this.store.getMulti();
|
|
141
|
-
await this.setState(multi);
|
|
142
|
-
await CollatorService.notarizeContinuation(this, multi);
|
|
143
|
-
|
|
144
|
-
await this.setStatus(0, multi);
|
|
145
|
-
const multiResponse = await multi.exec() as MultiResponseFlags;
|
|
146
|
-
telemetry.mapActivityAttributes();
|
|
147
|
-
const jobStatus = this.resolveStatus(multiResponse);
|
|
148
|
-
telemetry.setActivityAttributes({ 'app.job.jss': jobStatus });
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async processSuccess(telemetry: TelemetryService): Promise<void> {
|
|
152
|
-
this.bindActivityData('output');
|
|
153
|
-
this.adjacencyList = await this.filterAdjacent();
|
|
154
|
-
this.mapJobData();
|
|
155
|
-
const multi = this.store.getMulti();
|
|
156
|
-
await this.setState(multi);
|
|
157
|
-
await CollatorService.notarizeCompletion(this, multi);
|
|
158
|
-
|
|
159
|
-
await this.setStatus(this.adjacencyList.length - 1, multi);
|
|
160
|
-
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);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
async processError(telemetry: TelemetryService): Promise<void> {
|
|
172
|
-
this.bindActivityError(this.data);
|
|
173
|
-
this.adjacencyList = await this.filterAdjacent();
|
|
174
|
-
const multi = this.store.getMulti();
|
|
175
|
-
await this.setState(multi);
|
|
176
|
-
await CollatorService.notarizeCompletion(this, multi);
|
|
177
|
-
|
|
178
|
-
await this.setStatus(this.adjacencyList.length - 1, multi);
|
|
179
|
-
const multiResponse = await multi.exec() as MultiResponseFlags;
|
|
180
|
-
telemetry.mapActivityAttributes();
|
|
181
|
-
const jobStatus = this.resolveStatus(multiResponse);
|
|
182
|
-
const attrs: StringScalarType = { 'app.job.jss': jobStatus };
|
|
183
|
-
const messageIds = await this.transition(this.adjacencyList, jobStatus);
|
|
184
|
-
if (messageIds.length) {
|
|
185
|
-
attrs['app.activity.mids'] = messageIds.join(',')
|
|
186
|
-
}
|
|
187
|
-
telemetry.setActivityAttributes(attrs);
|
|
188
|
-
}
|
|
189
94
|
}
|
|
190
95
|
|
|
191
96
|
export { Worker };
|
|
@@ -4,22 +4,45 @@ import { CollationFaultType, CollationStage } from '../../types/collator';
|
|
|
4
4
|
import { ActivityDuplex } from '../../types/activity';
|
|
5
5
|
import { HotMeshGraph } from '../../types/hotmesh';
|
|
6
6
|
import { Activity } from '../activities/activity';
|
|
7
|
+
import { Cycle } from '../activities/cycle';
|
|
7
8
|
|
|
8
9
|
class CollatorService {
|
|
9
10
|
|
|
10
11
|
//max int digit count that supports `hincrby`
|
|
11
12
|
static targetLength = 15;
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
/**
|
|
15
|
+
* returns the dimensional address (dad) for the target; due
|
|
16
|
+
* to the nature of the notary system, the dad for leg 2 entry
|
|
17
|
+
* must target the `0` index while leg 2 exit must target the
|
|
18
|
+
* current index (0)
|
|
19
|
+
*/
|
|
20
|
+
static getDimensionalAddress(activity: Activity, isEntry = false): Record<string, string> {
|
|
14
21
|
let dad = activity.context.metadata.dad || activity.metadata.dad;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// dad = `${dad.substring(0, dad.lastIndexOf(','))},0`;
|
|
19
|
-
// }
|
|
22
|
+
if (isEntry && dad && activity.leg === 2) {
|
|
23
|
+
dad = `${dad.substring(0, dad.lastIndexOf(','))},0`;
|
|
24
|
+
}
|
|
20
25
|
return CollatorService.getDimensionsById([...activity.config.ancestors, activity.metadata.aid], dad);
|
|
21
26
|
}
|
|
22
27
|
|
|
28
|
+
/**
|
|
29
|
+
* resolves the dimensional address for the
|
|
30
|
+
* ancestor in the graph to go back to. this address
|
|
31
|
+
* is determined by trimming the last digits from
|
|
32
|
+
* the `dad` (including the target).
|
|
33
|
+
* the target activity index is then set to `0`, so that
|
|
34
|
+
* the origin node can be queried for approval/entry.
|
|
35
|
+
*/
|
|
36
|
+
static resolveReentryDimension(activity: Cycle) {
|
|
37
|
+
const targetActivityId = activity.config.ancestor;
|
|
38
|
+
const ancestors = activity.config.ancestors;
|
|
39
|
+
const ancestorIndex = ancestors.indexOf(targetActivityId);
|
|
40
|
+
const dimensions = activity.metadata.dad.split(','); //e.g., `,0,0,1,0`
|
|
41
|
+
dimensions.length = ancestorIndex + 1;
|
|
42
|
+
dimensions.push('0');
|
|
43
|
+
return dimensions.join(',');
|
|
44
|
+
}
|
|
45
|
+
|
|
23
46
|
static async notarizeEntry(activity: Activity, multi?: RedisMulti): Promise<number> {
|
|
24
47
|
//decrement by -100_000_000_000_000
|
|
25
48
|
const amount = await activity.store.collate(activity.context.metadata.jid, activity.metadata.aid, -100_000_000_000_000, this.getDimensionalAddress(activity), multi);
|
|
@@ -35,14 +58,21 @@ class CollatorService {
|
|
|
35
58
|
return amount;
|
|
36
59
|
}
|
|
37
60
|
|
|
61
|
+
static async notarizeEarlyExit(activity: Activity, multi?: RedisMulti): Promise<number> {
|
|
62
|
+
//decrement the 2nd and 3rd digits to fully deactivate (`cycle` activities use this command to fully exit after leg 1) (should result in `888000000000000`)
|
|
63
|
+
return await activity.store.collate(activity.context.metadata.jid, activity.metadata.aid, -11_000_000_000_000, this.getDimensionalAddress(activity), multi);
|
|
64
|
+
};
|
|
65
|
+
|
|
38
66
|
static async notarizeEarlyCompletion(activity: Activity, multi?: RedisMulti): Promise<number> {
|
|
39
|
-
//initialize both `possible` (1m) and `actualized` (1) zero dimension, while decrementing the 2nd
|
|
40
|
-
|
|
67
|
+
//initialize both `possible` (1m) and `actualized` (1) zero dimension, while decrementing the 2nd
|
|
68
|
+
//3rd digit is optionally kept open if the activity might be used in a cycle
|
|
69
|
+
const decrement = activity.config.cycle ? 10_000_000_000_000 : 11_000_000_000_000;
|
|
70
|
+
return await activity.store.collate(activity.context.metadata.jid, activity.metadata.aid, 1_000_001 - decrement, this.getDimensionalAddress(activity), multi);
|
|
41
71
|
};
|
|
42
72
|
|
|
43
73
|
static async notarizeReentry(activity: Activity, multi?: RedisMulti): Promise<number> {
|
|
44
74
|
//increment by 1_000_000 (indicates re-entry and is used to drive the 'dimensional address' for adjacent activities (minus 1))
|
|
45
|
-
const amount = await activity.store.collate(activity.context.metadata.jid, activity.metadata.aid, 1_000_000, this.getDimensionalAddress(activity), multi);
|
|
75
|
+
const amount = await activity.store.collate(activity.context.metadata.jid, activity.metadata.aid, 1_000_000, this.getDimensionalAddress(activity, true), multi);
|
|
46
76
|
this.verifyInteger(amount, 2, 'enter');
|
|
47
77
|
return amount;
|
|
48
78
|
};
|
|
@@ -53,8 +83,10 @@ class CollatorService {
|
|
|
53
83
|
};
|
|
54
84
|
|
|
55
85
|
static async notarizeCompletion(activity: Activity, multi?: RedisMulti): Promise<number> {
|
|
56
|
-
//
|
|
57
|
-
|
|
86
|
+
//1) ALWAYS actualize leg2 dimension (+1)
|
|
87
|
+
//2) IF the activity is used in a cycle, don't close leg 2!
|
|
88
|
+
const decrement = activity.config.cycle ? 0 : -1_000_000_000_000;
|
|
89
|
+
return await activity.store.collate(activity.context.metadata.jid, activity.metadata.aid, 1 - decrement, this.getDimensionalAddress(activity), multi);
|
|
58
90
|
};
|
|
59
91
|
|
|
60
92
|
static getDigitAtIndex(num: number, targetDigitIndex: number): number | null {
|
|
@@ -26,7 +26,12 @@ const getWorkflowYAML = (topic: string, version = '1') => {
|
|
|
26
26
|
type: trigger
|
|
27
27
|
stats:
|
|
28
28
|
id: '{$self.input.data.workflowId}'
|
|
29
|
+
|
|
29
30
|
a1:
|
|
31
|
+
type: activity
|
|
32
|
+
cycle: true
|
|
33
|
+
|
|
34
|
+
w1:
|
|
30
35
|
type: worker
|
|
31
36
|
topic: ${topic}
|
|
32
37
|
input:
|
|
@@ -49,9 +54,20 @@ const getWorkflowYAML = (topic: string, version = '1') => {
|
|
|
49
54
|
job:
|
|
50
55
|
maps:
|
|
51
56
|
response: '{$self.output.data.response}'
|
|
57
|
+
|
|
58
|
+
c1:
|
|
59
|
+
type: cycle
|
|
60
|
+
ancestor: a1
|
|
52
61
|
transitions:
|
|
53
62
|
t1:
|
|
54
|
-
- to: a1
|
|
63
|
+
- to: a1
|
|
64
|
+
a1:
|
|
65
|
+
- to: w1
|
|
66
|
+
w1:
|
|
67
|
+
- to: c1
|
|
68
|
+
conditions:
|
|
69
|
+
code: 500
|
|
70
|
+
`;
|
|
55
71
|
}
|
|
56
72
|
|
|
57
73
|
const getActivityYAML = (topic: string, version = '1') => {
|
|
@@ -44,6 +44,7 @@ export class WorkerService {
|
|
|
44
44
|
static connection: Connection;
|
|
45
45
|
static instances = new Map<string, HotMesh | Promise<HotMesh>>();
|
|
46
46
|
workflowRunner: HotMesh;
|
|
47
|
+
activityRunner: HotMesh;
|
|
47
48
|
|
|
48
49
|
static getHotMesh = async (worflowTopic: string) => {
|
|
49
50
|
if (WorkerService.instances.has(worflowTopic)) {
|
|
@@ -92,17 +93,20 @@ export class WorkerService {
|
|
|
92
93
|
* allowing proxyActivities to succeed.
|
|
93
94
|
*/
|
|
94
95
|
static registerActivities<ACT>(activities: ACT): Registry {
|
|
95
|
-
|
|
96
|
-
WorkerService.activityRegistry[
|
|
97
|
-
}
|
|
96
|
+
if (typeof activities === 'function') {
|
|
97
|
+
WorkerService.activityRegistry[activities.name] = activities as Function;
|
|
98
|
+
} else {
|
|
99
|
+
Object.keys(activities).forEach(key => {
|
|
100
|
+
WorkerService.activityRegistry[activities[key].name] = (activities as any)[key] as Function;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
98
103
|
return WorkerService.activityRegistry;
|
|
99
104
|
}
|
|
100
105
|
|
|
101
106
|
static async create(config: WorkerConfig) {
|
|
107
|
+
//always call `registerActivities` before `import`
|
|
102
108
|
WorkerService.connection = config.connection;
|
|
103
|
-
//pre-cache user activity functions
|
|
104
109
|
WorkerService.registerActivities<typeof config.activities>(config.activities);
|
|
105
|
-
//import the user's workflow file (triggers activity functions to be wrapped)
|
|
106
110
|
const workflow = await import(config.workflowsPath);
|
|
107
111
|
const [workflowFunctionName, workflowFunction] = WorkerService.resolveWorkflowTarget(workflow);
|
|
108
112
|
const baseTopic = `${config.taskQueue}-${workflowFunctionName}`;
|
|
@@ -111,9 +115,8 @@ export class WorkerService {
|
|
|
111
115
|
|
|
112
116
|
//initialize supporting workflows
|
|
113
117
|
const worker = new WorkerService();
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
await WorkerService.activateWorkflow(activityRunner, activityTopic, getActivityYAML);
|
|
118
|
+
worker.activityRunner = await worker.initActivityWorkflow(config, activityTopic);
|
|
119
|
+
await WorkerService.activateWorkflow(worker.activityRunner, activityTopic, getActivityYAML);
|
|
117
120
|
worker.workflowRunner = await worker.initWorkerWorkflow(config, workflowTopic, workflowFunction);
|
|
118
121
|
await WorkerService.activateWorkflow(worker.workflowRunner, workflowTopic, getWorkflowYAML);
|
|
119
122
|
return worker;
|
|
@@ -132,11 +135,7 @@ export class WorkerService {
|
|
|
132
135
|
}
|
|
133
136
|
|
|
134
137
|
async run() {
|
|
135
|
-
|
|
136
|
-
this.workflowRunner.engine.logger.info('WorkerService is running');
|
|
137
|
-
} else {
|
|
138
|
-
console.log('WorkerService is running');
|
|
139
|
-
}
|
|
138
|
+
this.workflowRunner.engine.logger.info('WorkerService is running');
|
|
140
139
|
}
|
|
141
140
|
|
|
142
141
|
async initActivityWorkflow(config: WorkerConfig, activityTopic: string): Promise<HotMesh> {
|
|
@@ -173,10 +172,11 @@ export class WorkerService {
|
|
|
173
172
|
data: { response: pojoResponse }
|
|
174
173
|
};
|
|
175
174
|
} catch (err) {
|
|
176
|
-
|
|
177
|
-
//todo (make retry configurable)
|
|
175
|
+
this.activityRunner.engine.logger.error('durable-worker-activity-err', err);
|
|
178
176
|
return {
|
|
179
|
-
status: StreamStatus.
|
|
177
|
+
status: StreamStatus.ERROR,
|
|
178
|
+
code: 500,
|
|
179
|
+
message: err.message,
|
|
180
180
|
metadata: { ...data.metadata },
|
|
181
181
|
data: { error: err }
|
|
182
182
|
} as StreamDataResponse;
|
|
@@ -193,7 +193,7 @@ export class WorkerService {
|
|
|
193
193
|
await hotMesh.deploy(getActivityYAML(activityTopic, version));
|
|
194
194
|
await hotMesh.activate(version);
|
|
195
195
|
} catch (err) {
|
|
196
|
-
|
|
196
|
+
hotMesh.engine.logger.error('durable-worker-activity-deploy-activate-error', err);
|
|
197
197
|
throw err;
|
|
198
198
|
}
|
|
199
199
|
} else if(app && !app.active) {
|
|
@@ -258,10 +258,9 @@ export class WorkerService {
|
|
|
258
258
|
data: { response: workflowResponse }
|
|
259
259
|
};
|
|
260
260
|
} catch (err) {
|
|
261
|
-
//todo: (retryable error types)
|
|
262
261
|
return {
|
|
262
|
+
status: StreamStatus.ERROR,
|
|
263
263
|
code: 500,
|
|
264
|
-
status: StreamStatus.PENDING,
|
|
265
264
|
metadata: { ...data.metadata },
|
|
266
265
|
data: { error: err }
|
|
267
266
|
} as StreamDataResponse;
|
|
@@ -103,7 +103,10 @@ export class WorkflowService {
|
|
|
103
103
|
try {
|
|
104
104
|
const hmshInstance = await WorkerService.getHotMesh(activityTopic);
|
|
105
105
|
activityState = await hmshInstance.getState(activityTopic, activityJobId);
|
|
106
|
-
if (activityState.metadata.
|
|
106
|
+
if (activityState.metadata.err) {
|
|
107
|
+
await hmshInstance.scrub(activityJobId);
|
|
108
|
+
throw new Error(activityState.metadata.err);
|
|
109
|
+
} else if (activityState.metadata.js === 0) {
|
|
107
110
|
//return immediately
|
|
108
111
|
return activityState.data?.response as T;
|
|
109
112
|
}
|
package/services/mapper/index.ts
CHANGED
|
@@ -60,6 +60,9 @@ class MapperService {
|
|
|
60
60
|
return transitionRule;
|
|
61
61
|
}
|
|
62
62
|
if (code.toString() === (transitionRule.code || 200).toString()) {
|
|
63
|
+
if (!transitionRule.match) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
63
66
|
const orGate = transitionRule.gate === 'or';
|
|
64
67
|
let allAreTrue = true;
|
|
65
68
|
let someAreTrue = false;
|
package/types/activity.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MetricTypes } from "./stats";
|
|
2
2
|
import { StreamRetryPolicy } from "./stream";
|
|
3
3
|
|
|
4
|
-
type ActivityExecutionType = 'trigger' | 'await' | 'worker' | 'activity' | 'emit' | 'iterate';
|
|
4
|
+
type ActivityExecutionType = 'trigger' | 'await' | 'worker' | 'activity' | 'emit' | 'iterate' | 'cycle';
|
|
5
5
|
|
|
6
6
|
type Consumes = Record<string, string[]>;
|
|
7
7
|
|
|
@@ -18,6 +18,7 @@ interface BaseActivity {
|
|
|
18
18
|
sleep?: number; //@pipe /in seconds
|
|
19
19
|
expire?: number; //-1 forever (15 seconds default); todo: make globally configurable
|
|
20
20
|
retry?: StreamRetryPolicy
|
|
21
|
+
cycle?: boolean; //if true, the `notary` will leave leg 2 open, so it can be re/cycled
|
|
21
22
|
collationInt?: number; //compiler
|
|
22
23
|
consumes?: Consumes; //compiler
|
|
23
24
|
PRODUCES?: string[]; //compiler
|
|
@@ -61,6 +62,11 @@ interface EmitActivity extends BaseActivity {
|
|
|
61
62
|
type: 'emit';
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
interface CycleActivity extends BaseActivity {
|
|
66
|
+
type: 'cycle';
|
|
67
|
+
ancestor: string; //ancestor activity id
|
|
68
|
+
}
|
|
69
|
+
|
|
64
70
|
interface IterateActivity extends BaseActivity {
|
|
65
71
|
type: 'iterate';
|
|
66
72
|
}
|
|
@@ -108,6 +114,7 @@ export {
|
|
|
108
114
|
Consumes,
|
|
109
115
|
TriggerActivityStats,
|
|
110
116
|
AwaitActivity,
|
|
117
|
+
CycleActivity,
|
|
111
118
|
BaseActivity,
|
|
112
119
|
EmitActivity,
|
|
113
120
|
IterateActivity,
|