@hotmeshio/hotmesh 0.0.52 → 0.0.54
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/README.md +22 -18
- package/build/index.d.ts +1 -2
- package/build/index.js +1 -3
- package/build/modules/enums.d.ts +8 -3
- package/build/modules/enums.js +16 -8
- package/build/modules/errors.d.ts +58 -20
- package/build/modules/errors.js +90 -33
- package/build/package.json +7 -2
- package/build/services/activities/activity.d.ts +8 -0
- package/build/services/activities/activity.js +63 -14
- package/build/services/activities/await.js +6 -6
- package/build/services/activities/cycle.d.ts +2 -2
- package/build/services/activities/cycle.js +5 -5
- package/build/services/activities/hook.js +9 -5
- package/build/services/activities/interrupt.d.ts +3 -3
- package/build/services/activities/interrupt.js +15 -6
- package/build/services/activities/signal.d.ts +2 -2
- package/build/services/activities/signal.js +4 -4
- package/build/services/activities/trigger.d.ts +5 -2
- package/build/services/activities/trigger.js +34 -4
- package/build/services/activities/worker.js +6 -6
- package/build/services/compiler/deployer.js +33 -5
- package/build/services/compiler/validator.d.ts +2 -0
- package/build/services/compiler/validator.js +5 -1
- package/build/services/durable/client.d.ts +7 -1
- package/build/services/durable/client.js +57 -38
- package/build/services/durable/exporter.d.ts +27 -81
- package/build/services/durable/exporter.js +153 -325
- package/build/services/durable/handle.d.ts +13 -8
- package/build/services/durable/handle.js +61 -48
- package/build/services/durable/index.d.ts +0 -2
- package/build/services/durable/index.js +0 -2
- package/build/services/durable/schemas/factory.d.ts +33 -0
- package/build/services/durable/schemas/factory.js +2356 -0
- package/build/services/durable/search.js +8 -8
- package/build/services/durable/worker.js +117 -25
- package/build/services/durable/workflow.d.ts +67 -52
- package/build/services/durable/workflow.js +322 -306
- package/build/services/engine/index.d.ts +2 -2
- package/build/services/engine/index.js +5 -2
- package/build/services/exporter/index.d.ts +2 -4
- package/build/services/exporter/index.js +4 -5
- package/build/services/hotmesh/index.d.ts +2 -2
- package/build/services/hotmesh/index.js +2 -2
- package/build/services/mapper/index.d.ts +6 -2
- package/build/services/mapper/index.js +6 -2
- package/build/services/pipe/functions/array.d.ts +2 -10
- package/build/services/pipe/functions/array.js +30 -28
- package/build/services/pipe/functions/conditional.d.ts +1 -0
- package/build/services/pipe/functions/conditional.js +3 -0
- package/build/services/pipe/functions/date.d.ts +1 -0
- package/build/services/pipe/functions/date.js +4 -0
- package/build/services/pipe/functions/index.d.ts +2 -0
- package/build/services/pipe/functions/index.js +2 -0
- package/build/services/pipe/functions/logical.d.ts +5 -0
- package/build/services/pipe/functions/logical.js +12 -0
- package/build/services/pipe/functions/object.d.ts +3 -0
- package/build/services/pipe/functions/object.js +25 -7
- package/build/services/pipe/index.d.ts +20 -3
- package/build/services/pipe/index.js +82 -16
- package/build/services/router/index.js +14 -3
- package/build/services/serializer/index.d.ts +3 -2
- package/build/services/serializer/index.js +11 -4
- package/build/services/store/clients/ioredis.js +6 -6
- package/build/services/store/clients/redis.js +7 -7
- package/build/services/store/index.d.ts +2 -0
- package/build/services/store/index.js +4 -1
- package/build/services/stream/clients/ioredis.js +8 -8
- package/build/services/stream/clients/redis.js +1 -1
- package/build/types/activity.d.ts +60 -5
- package/build/types/durable.d.ts +183 -36
- package/build/types/error.d.ts +48 -0
- package/build/types/error.js +2 -0
- package/build/types/exporter.d.ts +35 -7
- package/build/types/index.d.ts +4 -3
- package/build/types/job.d.ts +93 -6
- package/build/types/pipe.d.ts +81 -3
- package/build/types/stream.d.ts +61 -1
- package/build/types/stream.js +4 -0
- package/index.ts +1 -2
- package/modules/enums.ts +16 -8
- package/modules/errors.ts +139 -34
- package/package.json +7 -2
- package/services/activities/activity.ts +63 -14
- package/services/activities/await.ts +6 -6
- package/services/activities/cycle.ts +7 -6
- package/services/activities/hook.ts +12 -5
- package/services/activities/interrupt.ts +19 -9
- package/services/activities/signal.ts +6 -5
- package/services/activities/trigger.ts +43 -6
- package/services/activities/worker.ts +7 -7
- package/services/compiler/deployer.ts +33 -6
- package/services/compiler/validator.ts +7 -3
- package/services/durable/client.ts +49 -22
- package/services/durable/exporter.ts +162 -349
- package/services/durable/handle.ts +66 -53
- package/services/durable/index.ts +0 -2
- package/services/durable/schemas/factory.ts +2358 -0
- package/services/durable/search.ts +8 -8
- package/services/durable/worker.ts +128 -29
- package/services/durable/workflow.ts +371 -322
- package/services/engine/index.ts +8 -3
- package/services/exporter/index.ts +10 -12
- package/services/hotmesh/index.ts +4 -3
- package/services/mapper/index.ts +6 -2
- package/services/pipe/functions/array.ts +24 -37
- package/services/pipe/functions/conditional.ts +4 -0
- package/services/pipe/functions/date.ts +6 -0
- package/services/pipe/functions/index.ts +7 -5
- package/services/pipe/functions/logical.ts +11 -0
- package/services/pipe/functions/object.ts +26 -7
- package/services/pipe/index.ts +99 -21
- package/services/quorum/index.ts +1 -3
- package/services/router/index.ts +14 -3
- package/services/serializer/index.ts +12 -5
- package/services/store/clients/ioredis.ts +6 -6
- package/services/store/clients/redis.ts +7 -7
- package/services/store/index.ts +4 -1
- package/services/stream/clients/ioredis.ts +8 -8
- package/services/stream/clients/redis.ts +1 -1
- package/types/activity.ts +87 -15
- package/types/durable.ts +263 -75
- package/types/error.ts +52 -0
- package/types/exporter.ts +43 -9
- package/types/index.ts +14 -8
- package/types/job.ts +157 -36
- package/types/pipe.ts +84 -3
- package/types/stream.ts +82 -23
- package/build/services/durable/factory.d.ts +0 -17
- package/build/services/durable/factory.js +0 -817
- package/build/services/durable/meshos.d.ts +0 -127
- package/build/services/durable/meshos.js +0 -380
- package/services/durable/factory.ts +0 -818
- package/services/durable/meshos.ts +0 -441
|
@@ -1,419 +1,232 @@
|
|
|
1
|
+
import { restoreHierarchy } from '../../modules/utils';
|
|
1
2
|
import { ILogger } from '../logger';
|
|
3
|
+
import { SerializerService } from '../serializer';
|
|
2
4
|
import { StoreService } from '../store';
|
|
3
|
-
import { StringStringType, Symbols } from "../../types";
|
|
4
|
-
import { RedisClient, RedisMulti } from '../../types/redis';
|
|
5
5
|
import {
|
|
6
|
-
ActivityAction,
|
|
7
|
-
DependencyExport,
|
|
8
|
-
ExportItem,
|
|
9
6
|
ExportOptions,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { VALSEP } from '../../modules/key';
|
|
7
|
+
DurableJobExport,
|
|
8
|
+
TimelineType,
|
|
9
|
+
TransitionType,
|
|
10
|
+
ExportFields} from '../../types/exporter';
|
|
11
|
+
import { RedisClient, RedisMulti } from '../../types/redis';
|
|
12
|
+
import { StringAnyType, StringStringType, Symbols } from "../../types/serializer";
|
|
17
13
|
|
|
18
|
-
/**
|
|
19
|
-
* Downloads job data from Redis (hscan, hmget, hgetall)
|
|
20
|
-
* Splits, Inflates, and Sorts the job data for use in durable contexts
|
|
21
|
-
*/
|
|
22
14
|
class ExporterService {
|
|
23
15
|
appId: string;
|
|
24
16
|
logger: ILogger;
|
|
25
|
-
serializer: SerializerService
|
|
26
17
|
store: StoreService<RedisClient, RedisMulti>;
|
|
27
18
|
symbols: Promise<Symbols> | Symbols;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Friendly names for the activity ids
|
|
31
|
-
*/
|
|
32
|
-
activitySymbols: Symbols = {
|
|
33
|
-
t1: 'trigger',
|
|
34
|
-
a1: 'pivot',
|
|
35
|
-
w1: 'worker',
|
|
36
|
-
a592: 'sleeper',
|
|
37
|
-
a594: 'awaiter',
|
|
38
|
-
a599: 'retryer',
|
|
39
|
-
c592: 'sleep_cycler',
|
|
40
|
-
c594: 'await_cycler',
|
|
41
|
-
c599: 'retry_cycler',
|
|
42
|
-
s5: 'scrubber',
|
|
43
|
-
sig: 'hook',
|
|
44
|
-
siga1: 'hook_pivot',
|
|
45
|
-
sigw1: 'hook_worker',
|
|
46
|
-
siga592: 'hook_sleeper',
|
|
47
|
-
siga594: 'hook_awaiter',
|
|
48
|
-
siga599: 'hook_retryer',
|
|
49
|
-
sigc592: 'hook_sleep_cycler',
|
|
50
|
-
sigc594: 'hook_await_cycler',
|
|
51
|
-
sigc599: 'hook_retry_cycler',
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
//adjacent transitions
|
|
55
|
-
transitions = {
|
|
56
|
-
trigger: ['pivot', 'hook'],
|
|
57
|
-
pivot: ['worker'],
|
|
58
|
-
worker: ['sleeper', 'awaiter', 'retryer', 'scrubber'],
|
|
59
|
-
sleeper: ['sleep_cycler'],
|
|
60
|
-
awaiter: ['await_cycler'],
|
|
61
|
-
retryer: ['retry_cycler'],
|
|
62
|
-
hook: ['hook_pivot'],
|
|
63
|
-
hook_pivot: ['hook_worker'],
|
|
64
|
-
hook_worker: ['hook_sleeper', 'hook_awaiter', 'hook_retryer'],
|
|
65
|
-
hook_sleeper: ['hook_sleep_cycler'],
|
|
66
|
-
hook_awaiter: ['hook_await_cycler'],
|
|
67
|
-
hook_retryer: ['hook_retry_cycler'],
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
//goto transitions
|
|
71
|
-
cycles = {
|
|
72
|
-
sleep_cycler: ['pivot'],
|
|
73
|
-
await_cycler: ['pivot'],
|
|
74
|
-
retry_cycler: ['pivot'],
|
|
75
|
-
hook_sleep_cycler: ['hook_pivot'],
|
|
76
|
-
hook_await_cycler: ['hook_pivot'],
|
|
77
|
-
hook_retry_cycler: ['hook_pivot'],
|
|
78
|
-
}
|
|
19
|
+
private static symbols: Map<string, Symbols> = new Map();
|
|
79
20
|
|
|
80
21
|
constructor(appId: string, store: StoreService<RedisClient, RedisMulti>, logger: ILogger) {
|
|
81
22
|
this.appId = appId;
|
|
82
23
|
this.logger = logger;
|
|
83
24
|
this.store = store;
|
|
84
|
-
this.serializer = new SerializerService();
|
|
85
25
|
}
|
|
86
26
|
|
|
87
27
|
/**
|
|
88
|
-
* Convert the job hash
|
|
89
|
-
*
|
|
90
|
-
* in terms relevant to narrative storytelling.
|
|
28
|
+
* Convert the job hash from its compiles format into a DurableJobExport object with
|
|
29
|
+
* facets that describe the workflow in terms relevant to narrative storytelling.
|
|
91
30
|
*/
|
|
92
31
|
async export(jobId: string, options: ExportOptions = {}): Promise<DurableJobExport> {
|
|
93
|
-
if (!this.
|
|
94
|
-
|
|
95
|
-
this.
|
|
32
|
+
if (!ExporterService.symbols.has(this.appId)) {
|
|
33
|
+
const symbols: Symbols | Promise<Symbols> = this.store.getAllSymbols();
|
|
34
|
+
ExporterService.symbols.set(this.appId, await symbols);
|
|
96
35
|
}
|
|
97
|
-
const depData = await this.store.getDependencies(jobId);
|
|
98
36
|
const jobData = await this.store.getRaw(jobId);
|
|
99
|
-
const jobExport = this.inflate(jobData,
|
|
37
|
+
const jobExport = this.inflate(jobData, options);
|
|
100
38
|
return jobExport;
|
|
101
39
|
}
|
|
102
40
|
|
|
103
41
|
/**
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* create an animated narrative of the job, highlighting
|
|
109
|
-
* activities in the graph according to the timeline's
|
|
110
|
-
* activity-created (/ac) and activity-updated (/au) entries.
|
|
42
|
+
* Inflates the job data from Redis into a DurableJobExport object
|
|
43
|
+
* @param jobHash - the job data from Redis
|
|
44
|
+
* @param dependencyList - the list of dependencies for the job
|
|
45
|
+
* @returns - the inflated job data
|
|
111
46
|
*/
|
|
112
|
-
|
|
113
|
-
const timeline:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
created: timestamp,
|
|
126
|
-
updated: timestamp,
|
|
127
|
-
};
|
|
128
|
-
const prior = timeline[timeline.length - 1];
|
|
129
|
-
if (prior && prior.activity === event.activity && prior.duplex !== event.duplex && prior.dimension === event.dimension) {
|
|
130
|
-
if (event.duplex === 'exit') {
|
|
131
|
-
prior.updated = event.timestamp;
|
|
132
|
-
} else {
|
|
133
|
-
prior.created = event.timestamp;
|
|
134
|
-
}
|
|
135
|
-
event = prior;
|
|
136
|
-
} else {
|
|
137
|
-
timeline.push(event);
|
|
138
|
-
}
|
|
47
|
+
inflate(jobHash: StringStringType, options: ExportOptions): DurableJobExport {
|
|
48
|
+
const timeline: TimelineType[] = [];
|
|
49
|
+
const state: StringAnyType = {};
|
|
50
|
+
const data: StringStringType = {};
|
|
51
|
+
const transitionsObject: Record<string, TransitionType> = {};
|
|
52
|
+
const regex = /^([a-zA-Z]{3}),(\d+(?:,\d+)*)/;
|
|
53
|
+
|
|
54
|
+
Object.entries(jobHash).forEach(([key, value]) => {
|
|
55
|
+
const match = key.match(regex);
|
|
56
|
+
|
|
57
|
+
if (match) {
|
|
58
|
+
//transitions
|
|
59
|
+
this.inflateTransition(match, value, transitionsObject);
|
|
139
60
|
|
|
140
|
-
if (
|
|
141
|
-
|
|
142
|
-
this.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
61
|
+
} else if (key.length === 3) {
|
|
62
|
+
//state
|
|
63
|
+
state[this.inflateKey(key)] = SerializerService.fromString(value);
|
|
64
|
+
|
|
65
|
+
} else if (key.startsWith('_')) {
|
|
66
|
+
//data
|
|
67
|
+
data[key.substring(1)] = value;
|
|
68
|
+
|
|
69
|
+
} else if (key.startsWith('-')) {
|
|
70
|
+
//timeline
|
|
71
|
+
const keyParts = this.keyToObject(key); //key parts have meaning
|
|
72
|
+
timeline.push({
|
|
73
|
+
...keyParts,
|
|
74
|
+
key,
|
|
75
|
+
value: this.resolveValue(value, options.values),
|
|
76
|
+
});
|
|
148
77
|
}
|
|
149
78
|
});
|
|
150
|
-
|
|
79
|
+
|
|
80
|
+
return this.filterFields({
|
|
81
|
+
data: restoreHierarchy(data),
|
|
82
|
+
state: Object.entries(restoreHierarchy(state))[0][1],
|
|
83
|
+
status: parseInt(jobHash[':'], 10),
|
|
84
|
+
timeline: this.sortParts(timeline),
|
|
85
|
+
transitions: this.sortEntriesByCreated(transitionsObject),
|
|
86
|
+
}, options.block, options.allow);
|
|
151
87
|
}
|
|
152
88
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if (
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
break;
|
|
165
|
-
}
|
|
89
|
+
resolveValue(raw: string, withValues: boolean): Record<string, any> | string | number | null {
|
|
90
|
+
const resolved = SerializerService.fromString(raw);
|
|
91
|
+
if (withValues !== false) {
|
|
92
|
+
return resolved;
|
|
93
|
+
}
|
|
94
|
+
if (resolved && typeof resolved === 'object') {
|
|
95
|
+
if ('data' in resolved) {
|
|
96
|
+
resolved.data = {};
|
|
97
|
+
}
|
|
98
|
+
if ('$error' in resolved) {
|
|
99
|
+
resolved.$error = {};
|
|
166
100
|
}
|
|
167
101
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
isPausingAction(actionType: string): boolean {
|
|
171
|
-
return actionType === 'sleep' || actionType === 'waitForSignal';
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
isMainEntry(key: string): boolean {
|
|
175
|
-
return key.startsWith('worker/') && key.endsWith('/ac');
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
isHookEntry(key: string): boolean {
|
|
179
|
-
return key.startsWith('hook_worker/') && key.endsWith('/ac');
|
|
102
|
+
return resolved;
|
|
180
103
|
}
|
|
181
104
|
|
|
182
105
|
/**
|
|
183
106
|
* Inflates the key from Redis, 3-character symbol
|
|
184
107
|
* into a human-readable JSON path, reflecting the
|
|
185
108
|
* tree-like structure of the unidimensional Hash
|
|
109
|
+
* @private
|
|
186
110
|
*/
|
|
187
111
|
inflateKey(key: string): string {
|
|
188
|
-
|
|
189
|
-
|
|
112
|
+
const symbols = ExporterService.symbols.get(this.appId);
|
|
113
|
+
if (key in symbols) {
|
|
114
|
+
const path = symbols[key];
|
|
190
115
|
const parts = path.split('/');
|
|
191
|
-
if (parts[0] in this.activitySymbols) {
|
|
192
|
-
parts[0] = this.activitySymbols[parts[0]];
|
|
193
|
-
}
|
|
194
116
|
return parts.join('/');
|
|
195
117
|
}
|
|
196
118
|
return key;
|
|
197
119
|
}
|
|
198
120
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
*/
|
|
206
|
-
inflateDependencyData(data: string[], actions: JobActionExport): DependencyExport[] {
|
|
207
|
-
const hookReg = /([0-9,]+)-(\d+)$/;
|
|
208
|
-
const flowReg = /-(\d+)$/;
|
|
209
|
-
return data.map((dependency, index: number): DependencyExport => {
|
|
210
|
-
const [action, topic, gid, _pd, ...jid] = dependency.split(VALSEP);
|
|
211
|
-
const jobId = jid.join(VALSEP);
|
|
212
|
-
const match = jobId.match(hookReg);
|
|
213
|
-
let prefix: string;
|
|
214
|
-
let type: 'hook' | 'flow' | 'other';
|
|
215
|
-
let dimensionKey: string = '';
|
|
216
|
-
if (match) {
|
|
217
|
-
//hook-originating dependency
|
|
218
|
-
const [_, dimension, counter] = match;
|
|
219
|
-
dimensionKey = dimension.split(',').join('/');
|
|
220
|
-
prefix = `${dimensionKey}[${counter}]`;
|
|
221
|
-
type = 'hook';
|
|
222
|
-
} else {
|
|
223
|
-
const match = jobId.match(flowReg);
|
|
224
|
-
if (match) {
|
|
225
|
-
//main workflow-originating dependency
|
|
226
|
-
const [_, counter] = match;
|
|
227
|
-
prefix = `[${counter}]`;
|
|
228
|
-
type = 'flow';
|
|
229
|
-
} else {
|
|
230
|
-
//'other' types like signal cleanup
|
|
231
|
-
prefix = '/';
|
|
232
|
-
type = 'other';
|
|
121
|
+
filterFields(fullObject: DurableJobExport, block: ExportFields[] = [], allow: ExportFields[] = []): Partial<DurableJobExport> {
|
|
122
|
+
let result: Partial<DurableJobExport> = {};
|
|
123
|
+
if (allow && allow.length > 0) {
|
|
124
|
+
allow.forEach(field => {
|
|
125
|
+
if (field in fullObject) {
|
|
126
|
+
result[field] = fullObject[field] as StringAnyType & number & TimelineType[] & TransitionType[];
|
|
233
127
|
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
actions,
|
|
243
|
-
jobId,
|
|
244
|
-
);
|
|
245
|
-
return {
|
|
246
|
-
type: action,
|
|
247
|
-
topic,
|
|
248
|
-
gid,
|
|
249
|
-
jid: jobId,
|
|
250
|
-
} as unknown as DependencyExport;
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* Adds historical actions (proxyActivity, executeChild)
|
|
256
|
-
* using the `dependency list` to determine
|
|
257
|
-
* after-the-fact what happened within the 'black-box'
|
|
258
|
-
* worker function. This is necessary to interleave the
|
|
259
|
-
* actions into the replay timeline, given that it isn't
|
|
260
|
-
* really possible to know the inner-workings of the user's
|
|
261
|
-
* function
|
|
262
|
-
*
|
|
263
|
-
*/
|
|
264
|
-
seedActions(type: 'flow'|'hook'|'other', action: string, topic: string, dep: string, prefix: string, dimensionKey: string, actions: JobActionExport, jobId: string) {
|
|
265
|
-
if (type !== 'other' && action === 'expire-child') {
|
|
266
|
-
let depType: string;
|
|
267
|
-
if (topic == `${this.appId}.activity.execute`) {
|
|
268
|
-
depType = 'proxyActivity';
|
|
269
|
-
} else if (topic == `${this.appId}.execute`) {
|
|
270
|
-
depType = 'executeChild';
|
|
271
|
-
} else if (topic == `${this.appId}.wfsc.execute`) {
|
|
272
|
-
depType = 'waitForSignal';
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
if (depType) {
|
|
276
|
-
if (type === 'flow') {
|
|
277
|
-
actions.main.items.push([prefix, depType, jobId]);
|
|
278
|
-
} else if (type === 'hook') {
|
|
279
|
-
if (!actions.hooks[dimensionKey]) {
|
|
280
|
-
actions.hooks[dimensionKey] = {
|
|
281
|
-
cursor: -1,
|
|
282
|
-
items: [],
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
actions.hooks[dimensionKey].items.push([prefix, depType, jobId]);
|
|
128
|
+
});
|
|
129
|
+
} else {
|
|
130
|
+
result = { ...fullObject };
|
|
131
|
+
}
|
|
132
|
+
if (block && block.length > 0) {
|
|
133
|
+
block.forEach(field => {
|
|
134
|
+
if (field in result) {
|
|
135
|
+
delete result[field];
|
|
286
136
|
}
|
|
287
|
-
}
|
|
137
|
+
});
|
|
288
138
|
}
|
|
139
|
+
return result as DurableJobExport;
|
|
289
140
|
}
|
|
290
141
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
//
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
Object.entries(jobHash).forEach(([key, value]) => {
|
|
311
|
-
const match = key.match(regex);
|
|
312
|
-
if (match) {
|
|
313
|
-
//activity process state
|
|
314
|
-
this.inflateProcess(match, value, replay);
|
|
315
|
-
} else if (key.length === 3) {
|
|
316
|
-
//job state
|
|
317
|
-
state[this.inflateKey(key)] = this.serializer.fromString(value);
|
|
318
|
-
} else if (key.startsWith('_')) {
|
|
319
|
-
//job data
|
|
320
|
-
data[key.substring(1)] = value;
|
|
321
|
-
} else if (key.startsWith('-')) {
|
|
322
|
-
//actions with side effect (replayable)
|
|
323
|
-
this.inflateActions(key, value, actions);
|
|
142
|
+
inflateTransition(match: RegExpMatchArray, value: string, transitionsObject: Record<string, TransitionType>) {
|
|
143
|
+
const [_, letters, dimensions] = match;
|
|
144
|
+
const path = this.inflateKey(letters);
|
|
145
|
+
const parts = path.split('/');
|
|
146
|
+
const activity = parts[0];
|
|
147
|
+
const isCreate = path.endsWith('/output/metadata/ac');
|
|
148
|
+
const isUpdate = path.endsWith('/output/metadata/au');
|
|
149
|
+
//for now only export activity start/stop; activity data would also be interesting
|
|
150
|
+
if (isCreate || isUpdate) {
|
|
151
|
+
const targetName = `${activity},${dimensions}`;
|
|
152
|
+
let target = transitionsObject[targetName];
|
|
153
|
+
if (!target) {
|
|
154
|
+
transitionsObject[targetName] = {
|
|
155
|
+
activity,
|
|
156
|
+
dimensions,
|
|
157
|
+
created: isCreate ? value : null,
|
|
158
|
+
updated: isUpdate ? value : null,
|
|
159
|
+
};
|
|
324
160
|
} else {
|
|
325
|
-
|
|
326
|
-
other.push([null, key, value]);
|
|
161
|
+
target[isCreate ? 'created' : 'updated'] = value;
|
|
327
162
|
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
replay.sort(this.dateSort)
|
|
331
|
-
actions.main.items.sort(this.reverseSort);
|
|
332
|
-
Object.entries(actions.hooks).forEach(([key, value]) => {
|
|
333
|
-
value.items.sort(this.reverseSort);
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
return {
|
|
337
|
-
data: restoreHierarchy(data),
|
|
338
|
-
dependencies,
|
|
339
|
-
state: Object.entries(restoreHierarchy(state))[0][1],
|
|
340
|
-
status: jobHash[':'],
|
|
341
|
-
timeline: this.createTimeline(replay, actions),
|
|
342
|
-
transitions: { ...this.transitions },
|
|
343
|
-
cycles: { ...this.cycles },
|
|
344
|
-
};
|
|
163
|
+
}
|
|
345
164
|
}
|
|
346
165
|
|
|
347
|
-
|
|
348
|
-
const [
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const resolved = this.serializer.fromString(value);
|
|
354
|
-
replay.push([
|
|
355
|
-
dimensions,
|
|
356
|
-
path,
|
|
357
|
-
resolved,
|
|
358
|
-
]);
|
|
359
|
-
}
|
|
166
|
+
sortEntriesByCreated(obj: { [key: string]: TransitionType }): TransitionType[] {
|
|
167
|
+
const entriesArray: TransitionType[] = Object.values(obj);
|
|
168
|
+
entriesArray.sort((a, b) => {
|
|
169
|
+
return (a.created || a.updated).localeCompare(b.created || b.updated);
|
|
170
|
+
});
|
|
171
|
+
return entriesArray;
|
|
360
172
|
}
|
|
361
173
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
dimensionKey = `/${dimensions.join('/')}`;
|
|
372
|
-
isHook = true;
|
|
373
|
-
}
|
|
374
|
-
let targetList: ExportItem[];
|
|
375
|
-
if (isHook) {
|
|
376
|
-
if (!actions.hooks[dimensionKey]) {
|
|
377
|
-
actions.hooks[dimensionKey] = {
|
|
378
|
-
cursor: -1,
|
|
379
|
-
items: [],
|
|
380
|
-
};
|
|
174
|
+
/**
|
|
175
|
+
* marker names are overloaded with details like sequence, type, etc
|
|
176
|
+
*/
|
|
177
|
+
keyToObject(key: string): {index: number, dimension?: string, secondary?: number} {
|
|
178
|
+
function extractDimension(label: string): string {
|
|
179
|
+
const parts = label.split(',');
|
|
180
|
+
if (parts.length > 1) {
|
|
181
|
+
parts.shift();
|
|
182
|
+
return parts.join(',');
|
|
381
183
|
}
|
|
382
|
-
targetList = actions.hooks[dimensionKey].items;
|
|
383
|
-
} else {
|
|
384
|
-
targetList = actions.main.items;
|
|
385
184
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
reverseSort(aKey: ExportItem, bKey: ExportItem) {
|
|
394
|
-
if (aKey[0] > bKey[0]) {
|
|
395
|
-
return 1;
|
|
396
|
-
} else if (aKey[0] < bKey[0]) {
|
|
397
|
-
return -1;
|
|
185
|
+
const parts = key.split('-');
|
|
186
|
+
if (parts.length === 4) {
|
|
187
|
+
//-proxy-5- -search-1-1-
|
|
188
|
+
return {
|
|
189
|
+
index: parseInt(parts[2], 10),
|
|
190
|
+
dimension: extractDimension(parts[1]),
|
|
191
|
+
}
|
|
398
192
|
} else {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
193
|
+
//-search,0,0-1-1- -proxy,0,0-1-
|
|
194
|
+
return {
|
|
195
|
+
index: parseInt(parts[2], 10),
|
|
196
|
+
secondary: parseInt(parts[3], 10),
|
|
197
|
+
dimension: extractDimension(parts[1]),
|
|
403
198
|
}
|
|
404
|
-
return 0;
|
|
405
199
|
}
|
|
406
200
|
}
|
|
407
201
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
202
|
+
/**
|
|
203
|
+
* idem list has a complicated sort order based on indexes and dimensions
|
|
204
|
+
*/
|
|
205
|
+
sortParts(parts: TimelineType[]): TimelineType[] {
|
|
206
|
+
return parts.sort((a, b) => {
|
|
207
|
+
const { dimension: aDim, index: aIdx, secondary: aSec } = a;
|
|
208
|
+
const { dimension: bDim, index: bIdx, secondary: bSec } = b;
|
|
209
|
+
|
|
210
|
+
if (aDim === undefined && bDim !== undefined) return -1;
|
|
211
|
+
if (aDim !== undefined && bDim === undefined) return 1;
|
|
212
|
+
if (aDim !== undefined && bDim !== undefined) {
|
|
213
|
+
if (aDim < bDim) return -1;
|
|
214
|
+
if (aDim > bDim) return 1;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (aIdx < bIdx) return -1;
|
|
218
|
+
if (aIdx > bIdx) return 1;
|
|
219
|
+
|
|
220
|
+
if (aSec === undefined && bSec !== undefined) return -1;
|
|
221
|
+
if (aSec !== undefined && bSec === undefined) return 1;
|
|
222
|
+
if (aSec !== undefined && bSec !== undefined) {
|
|
223
|
+
if (aSec < bSec) return -1;
|
|
224
|
+
if (aSec > bSec) return 1;
|
|
225
|
+
}
|
|
226
|
+
|
|
414
227
|
return 0;
|
|
415
|
-
}
|
|
416
|
-
}
|
|
228
|
+
});
|
|
229
|
+
};
|
|
417
230
|
}
|
|
418
231
|
|
|
419
232
|
export { ExporterService };
|