@hotmeshio/hotmesh 0.0.55 → 0.0.57
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 +1 -1
- package/build/modules/enums.js +1 -10
- package/build/modules/key.d.ts +0 -38
- package/build/modules/key.js +4 -46
- package/build/modules/utils.d.ts +0 -8
- package/build/modules/utils.js +0 -14
- package/build/package.json +11 -4
- package/build/services/activities/activity.d.ts +0 -28
- package/build/services/activities/activity.js +1 -46
- package/build/services/activities/await.js +0 -4
- package/build/services/activities/cycle.d.ts +0 -7
- package/build/services/activities/cycle.js +1 -16
- package/build/services/activities/hook.d.ts +0 -6
- package/build/services/activities/hook.js +2 -12
- package/build/services/activities/interrupt.js +0 -8
- package/build/services/activities/signal.d.ts +0 -6
- package/build/services/activities/signal.js +0 -15
- package/build/services/activities/trigger.d.ts +0 -4
- package/build/services/activities/trigger.js +1 -7
- package/build/services/activities/worker.js +0 -4
- package/build/services/collator/index.d.ts +0 -70
- package/build/services/collator/index.js +1 -91
- package/build/services/compiler/deployer.js +6 -38
- package/build/services/compiler/index.d.ts +0 -15
- package/build/services/compiler/index.js +0 -20
- package/build/services/compiler/validator.d.ts +0 -3
- package/build/services/compiler/validator.js +0 -25
- package/build/services/connector/clients/ioredis.d.ts +2 -2
- package/build/services/connector/clients/ioredis.js +0 -2
- package/build/services/connector/clients/redis.d.ts +4 -4
- package/build/services/connector/clients/redis.js +1 -3
- package/build/services/connector/index.d.ts +1 -1
- package/build/services/connector/index.js +0 -2
- package/build/services/durable/client.d.ts +1 -26
- package/build/services/durable/client.js +0 -56
- package/build/services/durable/exporter.d.ts +0 -22
- package/build/services/durable/exporter.js +1 -30
- package/build/services/durable/handle.d.ts +0 -36
- package/build/services/durable/handle.js +0 -46
- package/build/services/durable/index.d.ts +0 -4
- package/build/services/durable/index.js +0 -4
- package/build/services/durable/schemas/factory.d.ts +0 -29
- package/build/services/durable/schemas/factory.js +0 -29
- package/build/services/durable/search.d.ts +1 -36
- package/build/services/durable/search.js +56 -56
- package/build/services/durable/worker.js +2 -22
- package/build/services/durable/workflow.d.ts +0 -114
- package/build/services/durable/workflow.js +1 -141
- package/build/services/engine/index.d.ts +1 -6
- package/build/services/engine/index.js +1 -43
- package/build/services/exporter/index.d.ts +0 -27
- package/build/services/exporter/index.js +0 -33
- package/build/services/hotmesh/index.d.ts +2 -2
- package/build/services/hotmesh/index.js +1 -9
- package/build/services/logger/index.js +0 -2
- package/build/services/mapper/index.d.ts +0 -14
- package/build/services/mapper/index.js +0 -14
- package/build/services/pipe/functions/date.d.ts +0 -7
- package/build/services/pipe/functions/date.js +0 -7
- package/build/services/pipe/functions/math.js +0 -2
- package/build/services/pipe/index.d.ts +0 -15
- package/build/services/pipe/index.js +2 -23
- package/build/services/quorum/index.d.ts +0 -7
- package/build/services/quorum/index.js +0 -21
- package/build/services/reporter/index.d.ts +0 -5
- package/build/services/reporter/index.js +0 -9
- package/build/services/router/index.d.ts +0 -9
- package/build/services/router/index.js +2 -38
- package/build/services/serializer/index.js +7 -26
- package/build/services/store/cache.d.ts +0 -18
- package/build/services/store/cache.js +0 -18
- package/build/services/store/clients/ioredis.d.ts +1 -1
- package/build/services/store/clients/ioredis.js +0 -1
- package/build/services/store/clients/redis.d.ts +1 -1
- package/build/services/store/index.d.ts +0 -55
- package/build/services/store/index.js +5 -81
- package/build/services/stream/clients/ioredis.d.ts +1 -1
- package/build/services/stream/clients/ioredis.js +1 -4
- package/build/services/stream/clients/redis.d.ts +1 -1
- package/build/services/sub/clients/ioredis.d.ts +1 -1
- package/build/services/sub/clients/redis.d.ts +1 -1
- package/build/services/task/index.d.ts +0 -9
- package/build/services/task/index.js +0 -31
- package/build/services/telemetry/index.d.ts +0 -7
- package/build/services/telemetry/index.js +1 -13
- package/build/services/worker/index.d.ts +0 -4
- package/build/services/worker/index.js +2 -6
- package/build/types/activity.d.ts +0 -81
- package/build/types/durable.d.ts +26 -177
- package/build/types/exporter.d.ts +0 -13
- package/build/types/hotmesh.d.ts +4 -16
- package/build/types/hotmesh.js +0 -3
- package/build/types/index.d.ts +4 -6
- package/build/types/index.js +4 -3
- package/build/types/job.d.ts +1 -86
- package/build/types/pipe.d.ts +0 -65
- package/build/types/quorum.d.ts +15 -10
- package/build/types/redis.d.ts +225 -7
- package/build/types/redis.js +9 -0
- package/build/types/stream.d.ts +0 -58
- package/build/types/stream.js +0 -4
- package/package.json +11 -4
- package/types/durable.ts +131 -4
- package/types/hotmesh.ts +3 -6
- package/types/index.ts +23 -10
- package/types/job.ts +1 -1
- package/types/quorum.ts +22 -0
- package/types/redis.ts +267 -18
- package/build/types/ioredisclient.d.ts +0 -5
- package/build/types/ioredisclient.js +0 -5
- package/build/types/redisclient.d.ts +0 -26
- package/build/types/redisclient.js +0 -2
- package/modules/enums.ts +0 -62
- package/modules/errors.ts +0 -280
- package/modules/key.ts +0 -101
- package/modules/storage.ts +0 -3
- package/modules/utils.ts +0 -242
- package/services/activities/activity.ts +0 -589
- package/services/activities/await.ts +0 -113
- package/services/activities/cycle.ts +0 -115
- package/services/activities/hook.ts +0 -197
- package/services/activities/index.ts +0 -19
- package/services/activities/interrupt.ts +0 -172
- package/services/activities/signal.ts +0 -148
- package/services/activities/trigger.ts +0 -295
- package/services/activities/worker.ts +0 -107
- package/services/collator/README.md +0 -102
- package/services/collator/index.ts +0 -291
- package/services/compiler/deployer.ts +0 -504
- package/services/compiler/index.ts +0 -98
- package/services/compiler/validator.ts +0 -158
- package/services/connector/clients/ioredis.ts +0 -57
- package/services/connector/clients/redis.ts +0 -72
- package/services/connector/index.ts +0 -42
- package/services/durable/client.ts +0 -266
- package/services/durable/connection.ts +0 -10
- package/services/durable/exporter.ts +0 -232
- package/services/durable/handle.ts +0 -160
- package/services/durable/index.ts +0 -27
- package/services/durable/schemas/factory.ts +0 -2358
- package/services/durable/search.ts +0 -196
- package/services/durable/worker.ts +0 -401
- package/services/durable/workflow.ts +0 -557
- package/services/engine/index.ts +0 -761
- package/services/exporter/index.ts +0 -146
- package/services/hotmesh/index.ts +0 -237
- package/services/logger/index.ts +0 -79
- package/services/mapper/index.ts +0 -89
- package/services/pipe/functions/array.ts +0 -78
- package/services/pipe/functions/bitwise.ts +0 -27
- package/services/pipe/functions/conditional.ts +0 -35
- package/services/pipe/functions/date.ts +0 -220
- package/services/pipe/functions/index.ts +0 -27
- package/services/pipe/functions/json.ts +0 -11
- package/services/pipe/functions/logical.ts +0 -11
- package/services/pipe/functions/math.ts +0 -217
- package/services/pipe/functions/number.ts +0 -75
- package/services/pipe/functions/object.ts +0 -98
- package/services/pipe/functions/string.ts +0 -86
- package/services/pipe/functions/symbol.ts +0 -39
- package/services/pipe/functions/unary.ts +0 -19
- package/services/pipe/index.ts +0 -216
- package/services/quorum/index.ts +0 -319
- package/services/reporter/index.ts +0 -387
- package/services/router/index.ts +0 -426
- package/services/serializer/README.md +0 -10
- package/services/serializer/index.ts +0 -285
- package/services/store/cache.ts +0 -172
- package/services/store/clients/ioredis.ts +0 -145
- package/services/store/clients/redis.ts +0 -191
- package/services/store/index.ts +0 -1091
- package/services/stream/clients/ioredis.ts +0 -157
- package/services/stream/clients/redis.ts +0 -158
- package/services/stream/index.ts +0 -58
- package/services/sub/clients/ioredis.ts +0 -83
- package/services/sub/clients/redis.ts +0 -74
- package/services/sub/index.ts +0 -25
- package/services/task/index.ts +0 -250
- package/services/telemetry/index.ts +0 -273
- package/services/worker/index.ts +0 -248
- package/types/ioredisclient.ts +0 -10
- package/types/redisclient.ts +0 -30
|
@@ -10,42 +10,20 @@ declare class ExporterService {
|
|
|
10
10
|
symbols: Promise<Symbols> | Symbols;
|
|
11
11
|
private static symbols;
|
|
12
12
|
constructor(appId: string, store: StoreService<RedisClient, RedisMulti>, logger: ILogger);
|
|
13
|
-
/**
|
|
14
|
-
* Convert the job hash from its compiles format into a DurableJobExport object with
|
|
15
|
-
* facets that describe the workflow in terms relevant to narrative storytelling.
|
|
16
|
-
*/
|
|
17
13
|
export(jobId: string, options?: ExportOptions): Promise<DurableJobExport>;
|
|
18
|
-
/**
|
|
19
|
-
* Inflates the job data from Redis into a DurableJobExport object
|
|
20
|
-
* @param jobHash - the job data from Redis
|
|
21
|
-
* @param dependencyList - the list of dependencies for the job
|
|
22
|
-
* @returns - the inflated job data
|
|
23
|
-
*/
|
|
24
14
|
inflate(jobHash: StringStringType, options: ExportOptions): DurableJobExport;
|
|
25
15
|
resolveValue(raw: string, withValues: boolean): Record<string, any> | string | number | null;
|
|
26
|
-
/**
|
|
27
|
-
* Inflates the key from Redis, 3-character symbol
|
|
28
|
-
* into a human-readable JSON path, reflecting the
|
|
29
|
-
* tree-like structure of the unidimensional Hash
|
|
30
|
-
* @private
|
|
31
|
-
*/
|
|
32
16
|
inflateKey(key: string): string;
|
|
33
17
|
filterFields(fullObject: DurableJobExport, block?: ExportFields[], allow?: ExportFields[]): Partial<DurableJobExport>;
|
|
34
18
|
inflateTransition(match: RegExpMatchArray, value: string, transitionsObject: Record<string, TransitionType>): void;
|
|
35
19
|
sortEntriesByCreated(obj: {
|
|
36
20
|
[key: string]: TransitionType;
|
|
37
21
|
}): TransitionType[];
|
|
38
|
-
/**
|
|
39
|
-
* marker names are overloaded with details like sequence, type, etc
|
|
40
|
-
*/
|
|
41
22
|
keyToObject(key: string): {
|
|
42
23
|
index: number;
|
|
43
24
|
dimension?: string;
|
|
44
25
|
secondary?: number;
|
|
45
26
|
};
|
|
46
|
-
/**
|
|
47
|
-
* idem list has a complicated sort order based on indexes and dimensions
|
|
48
|
-
*/
|
|
49
27
|
sortParts(parts: TimelineType[]): TimelineType[];
|
|
50
28
|
}
|
|
51
29
|
export { ExporterService };
|
|
@@ -9,10 +9,6 @@ class ExporterService {
|
|
|
9
9
|
this.logger = logger;
|
|
10
10
|
this.store = store;
|
|
11
11
|
}
|
|
12
|
-
/**
|
|
13
|
-
* Convert the job hash from its compiles format into a DurableJobExport object with
|
|
14
|
-
* facets that describe the workflow in terms relevant to narrative storytelling.
|
|
15
|
-
*/
|
|
16
12
|
async export(jobId, options = {}) {
|
|
17
13
|
if (!ExporterService.symbols.has(this.appId)) {
|
|
18
14
|
const symbols = this.store.getAllSymbols();
|
|
@@ -22,12 +18,6 @@ class ExporterService {
|
|
|
22
18
|
const jobExport = this.inflate(jobData, options);
|
|
23
19
|
return jobExport;
|
|
24
20
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Inflates the job data from Redis into a DurableJobExport object
|
|
27
|
-
* @param jobHash - the job data from Redis
|
|
28
|
-
* @param dependencyList - the list of dependencies for the job
|
|
29
|
-
* @returns - the inflated job data
|
|
30
|
-
*/
|
|
31
21
|
inflate(jobHash, options) {
|
|
32
22
|
const timeline = [];
|
|
33
23
|
const state = {};
|
|
@@ -37,20 +27,16 @@ class ExporterService {
|
|
|
37
27
|
Object.entries(jobHash).forEach(([key, value]) => {
|
|
38
28
|
const match = key.match(regex);
|
|
39
29
|
if (match) {
|
|
40
|
-
//transitions
|
|
41
30
|
this.inflateTransition(match, value, transitionsObject);
|
|
42
31
|
}
|
|
43
32
|
else if (key.length === 3) {
|
|
44
|
-
//state
|
|
45
33
|
state[this.inflateKey(key)] = serializer_1.SerializerService.fromString(value);
|
|
46
34
|
}
|
|
47
35
|
else if (key.startsWith('_')) {
|
|
48
|
-
//data
|
|
49
36
|
data[key.substring(1)] = value;
|
|
50
37
|
}
|
|
51
38
|
else if (key.startsWith('-')) {
|
|
52
|
-
|
|
53
|
-
const keyParts = this.keyToObject(key); //key parts have meaning
|
|
39
|
+
const keyParts = this.keyToObject(key);
|
|
54
40
|
timeline.push({
|
|
55
41
|
...keyParts,
|
|
56
42
|
key,
|
|
@@ -81,12 +67,6 @@ class ExporterService {
|
|
|
81
67
|
}
|
|
82
68
|
return resolved;
|
|
83
69
|
}
|
|
84
|
-
/**
|
|
85
|
-
* Inflates the key from Redis, 3-character symbol
|
|
86
|
-
* into a human-readable JSON path, reflecting the
|
|
87
|
-
* tree-like structure of the unidimensional Hash
|
|
88
|
-
* @private
|
|
89
|
-
*/
|
|
90
70
|
inflateKey(key) {
|
|
91
71
|
const symbols = ExporterService.symbols.get(this.appId);
|
|
92
72
|
if (key in symbols) {
|
|
@@ -124,7 +104,6 @@ class ExporterService {
|
|
|
124
104
|
const activity = parts[0];
|
|
125
105
|
const isCreate = path.endsWith('/output/metadata/ac');
|
|
126
106
|
const isUpdate = path.endsWith('/output/metadata/au');
|
|
127
|
-
//for now only export activity start/stop; activity data would also be interesting
|
|
128
107
|
if (isCreate || isUpdate) {
|
|
129
108
|
const targetName = `${activity},${dimensions}`;
|
|
130
109
|
let target = transitionsObject[targetName];
|
|
@@ -148,9 +127,6 @@ class ExporterService {
|
|
|
148
127
|
});
|
|
149
128
|
return entriesArray;
|
|
150
129
|
}
|
|
151
|
-
/**
|
|
152
|
-
* marker names are overloaded with details like sequence, type, etc
|
|
153
|
-
*/
|
|
154
130
|
keyToObject(key) {
|
|
155
131
|
function extractDimension(label) {
|
|
156
132
|
const parts = label.split(',');
|
|
@@ -161,14 +137,12 @@ class ExporterService {
|
|
|
161
137
|
}
|
|
162
138
|
const parts = key.split('-');
|
|
163
139
|
if (parts.length === 4) {
|
|
164
|
-
//-proxy-5- -search-1-1-
|
|
165
140
|
return {
|
|
166
141
|
index: parseInt(parts[2], 10),
|
|
167
142
|
dimension: extractDimension(parts[1]),
|
|
168
143
|
};
|
|
169
144
|
}
|
|
170
145
|
else {
|
|
171
|
-
//-search,0,0-1-1- -proxy,0,0-1-
|
|
172
146
|
return {
|
|
173
147
|
index: parseInt(parts[2], 10),
|
|
174
148
|
secondary: parseInt(parts[3], 10),
|
|
@@ -176,9 +150,6 @@ class ExporterService {
|
|
|
176
150
|
};
|
|
177
151
|
}
|
|
178
152
|
}
|
|
179
|
-
/**
|
|
180
|
-
* idem list has a complicated sort order based on indexes and dimensions
|
|
181
|
-
*/
|
|
182
153
|
sortParts(parts) {
|
|
183
154
|
return parts.sort((a, b) => {
|
|
184
155
|
const { dimension: aDim, index: aIdx, secondary: aSec } = a;
|
|
@@ -10,47 +10,11 @@ export declare class WorkflowHandleService {
|
|
|
10
10
|
workflowId: string;
|
|
11
11
|
constructor(hotMesh: HotMesh, workflowTopic: string, workflowId: string);
|
|
12
12
|
export(options?: ExportOptions): Promise<DurableJobExport>;
|
|
13
|
-
/**
|
|
14
|
-
* Sends a signal to the workflow. This is a way to send
|
|
15
|
-
* a message to a workflow that is paused due to having
|
|
16
|
-
* executed `Durable.workflow.waitFor`. The workflow
|
|
17
|
-
* will awaken if no other signals are pending.
|
|
18
|
-
*/
|
|
19
13
|
signal(signalId: string, data: Record<any, any>): Promise<void>;
|
|
20
|
-
/**
|
|
21
|
-
* Returns the job state of the workflow. If the workflow has completed
|
|
22
|
-
* this is also the job output. If the workflow is still running, this
|
|
23
|
-
* is the current state of the job, but it may change depending upon
|
|
24
|
-
* the activities that remain.
|
|
25
|
-
*/
|
|
26
14
|
state(metadata?: boolean): Promise<Record<string, any>>;
|
|
27
|
-
/**
|
|
28
|
-
* Returns the current search state of the workflow. This is
|
|
29
|
-
* different than the job state or individual activity state.
|
|
30
|
-
* Search state represents name/value pairs that were added
|
|
31
|
-
* to the workflow. As the workflow is stored in a Redis hash,
|
|
32
|
-
* this is a way to store additional data that is indexed
|
|
33
|
-
* and searchable using the RediSearch module.
|
|
34
|
-
*/
|
|
35
15
|
queryState(fields: string[]): Promise<Record<string, any>>;
|
|
36
|
-
/**
|
|
37
|
-
* Returns the current status of the workflow. This is a semaphore
|
|
38
|
-
* value that represents the current state of the workflow, where
|
|
39
|
-
* 0 is complete and a negative value represents that the flow was
|
|
40
|
-
* interrupted.
|
|
41
|
-
*/
|
|
42
16
|
status(): Promise<number>;
|
|
43
|
-
/**
|
|
44
|
-
* Interrupts a running workflow. Standard Job Completion tasks will
|
|
45
|
-
* run. Subscribers will be notified and the job hash will be expired.
|
|
46
|
-
*/
|
|
47
17
|
interrupt(options?: JobInterruptOptions): Promise<string>;
|
|
48
|
-
/**
|
|
49
|
-
* Waits for the workflow to complete and returns the result. If
|
|
50
|
-
* the workflow response includes an error, this method will rethrow
|
|
51
|
-
* the error, including the stack trace if available.
|
|
52
|
-
* Wrap calls in a try/catch as necessary to avoid unhandled exceptions.
|
|
53
|
-
*/
|
|
54
18
|
result<T>(config?: {
|
|
55
19
|
state?: boolean;
|
|
56
20
|
throwOnError?: boolean;
|
|
@@ -12,21 +12,9 @@ class WorkflowHandleService {
|
|
|
12
12
|
async export(options) {
|
|
13
13
|
return this.exporter.export(this.workflowId, options);
|
|
14
14
|
}
|
|
15
|
-
/**
|
|
16
|
-
* Sends a signal to the workflow. This is a way to send
|
|
17
|
-
* a message to a workflow that is paused due to having
|
|
18
|
-
* executed `Durable.workflow.waitFor`. The workflow
|
|
19
|
-
* will awaken if no other signals are pending.
|
|
20
|
-
*/
|
|
21
15
|
async signal(signalId, data) {
|
|
22
16
|
await this.hotMesh.hook(`${this.hotMesh.appId}.wfs.signal`, { id: signalId, data });
|
|
23
17
|
}
|
|
24
|
-
/**
|
|
25
|
-
* Returns the job state of the workflow. If the workflow has completed
|
|
26
|
-
* this is also the job output. If the workflow is still running, this
|
|
27
|
-
* is the current state of the job, but it may change depending upon
|
|
28
|
-
* the activities that remain.
|
|
29
|
-
*/
|
|
30
18
|
async state(metadata = false) {
|
|
31
19
|
const state = await this.hotMesh.getState(`${this.hotMesh.appId}.execute`, this.workflowId);
|
|
32
20
|
if (!state.data && state.metadata.err) {
|
|
@@ -34,56 +22,25 @@ class WorkflowHandleService {
|
|
|
34
22
|
}
|
|
35
23
|
return metadata ? state : state.data;
|
|
36
24
|
}
|
|
37
|
-
/**
|
|
38
|
-
* Returns the current search state of the workflow. This is
|
|
39
|
-
* different than the job state or individual activity state.
|
|
40
|
-
* Search state represents name/value pairs that were added
|
|
41
|
-
* to the workflow. As the workflow is stored in a Redis hash,
|
|
42
|
-
* this is a way to store additional data that is indexed
|
|
43
|
-
* and searchable using the RediSearch module.
|
|
44
|
-
*/
|
|
45
25
|
async queryState(fields) {
|
|
46
26
|
return await this.hotMesh.getQueryState(this.workflowId, fields);
|
|
47
27
|
}
|
|
48
|
-
/**
|
|
49
|
-
* Returns the current status of the workflow. This is a semaphore
|
|
50
|
-
* value that represents the current state of the workflow, where
|
|
51
|
-
* 0 is complete and a negative value represents that the flow was
|
|
52
|
-
* interrupted.
|
|
53
|
-
*/
|
|
54
28
|
async status() {
|
|
55
29
|
return await this.hotMesh.getStatus(this.workflowId);
|
|
56
30
|
}
|
|
57
|
-
/**
|
|
58
|
-
* Interrupts a running workflow. Standard Job Completion tasks will
|
|
59
|
-
* run. Subscribers will be notified and the job hash will be expired.
|
|
60
|
-
*/
|
|
61
31
|
async interrupt(options) {
|
|
62
32
|
return await this.hotMesh.interrupt(`${this.hotMesh.appId}.execute`, this.workflowId, options);
|
|
63
33
|
}
|
|
64
|
-
/**
|
|
65
|
-
* Waits for the workflow to complete and returns the result. If
|
|
66
|
-
* the workflow response includes an error, this method will rethrow
|
|
67
|
-
* the error, including the stack trace if available.
|
|
68
|
-
* Wrap calls in a try/catch as necessary to avoid unhandled exceptions.
|
|
69
|
-
*/
|
|
70
34
|
async result(config) {
|
|
71
35
|
const topic = `${this.hotMesh.appId}.executed.${this.workflowId}`;
|
|
72
36
|
let isResolved = false;
|
|
73
37
|
return new Promise(async (resolve, reject) => {
|
|
74
|
-
/**
|
|
75
|
-
* rejects/resolves the promise based on the `throwOnError`
|
|
76
|
-
* default behavior is to throw if error
|
|
77
|
-
*/
|
|
78
38
|
const safeReject = (err) => {
|
|
79
39
|
if (config?.throwOnError === false) {
|
|
80
40
|
return resolve(err);
|
|
81
41
|
}
|
|
82
42
|
reject(err);
|
|
83
43
|
};
|
|
84
|
-
/**
|
|
85
|
-
* Common completion function that unsubscribes from the topic/returns
|
|
86
|
-
*/
|
|
87
44
|
const complete = async (response, err) => {
|
|
88
45
|
if (isResolved)
|
|
89
46
|
return;
|
|
@@ -106,7 +63,6 @@ class WorkflowHandleService {
|
|
|
106
63
|
}
|
|
107
64
|
resolve(response);
|
|
108
65
|
};
|
|
109
|
-
//more expensive; fetches the entire job, not just the `status`
|
|
110
66
|
if (config?.state) {
|
|
111
67
|
const state = await this.hotMesh.getState(`${this.hotMesh.appId}.execute`, this.workflowId);
|
|
112
68
|
if (state?.data?.done && !state.data?.$error) {
|
|
@@ -119,7 +75,6 @@ class WorkflowHandleService {
|
|
|
119
75
|
return complete(null, JSON.parse(state.metadata.err));
|
|
120
76
|
}
|
|
121
77
|
}
|
|
122
|
-
//subscribe to 'done' topic
|
|
123
78
|
this.hotMesh.sub(topic, async (_topic, state) => {
|
|
124
79
|
this.hotMesh.unsub(topic);
|
|
125
80
|
if (state.data.done && !state.data?.$error) {
|
|
@@ -133,7 +88,6 @@ class WorkflowHandleService {
|
|
|
133
88
|
return await complete(null, error);
|
|
134
89
|
}
|
|
135
90
|
});
|
|
136
|
-
//check state in case completed during wiring
|
|
137
91
|
const status = await this.hotMesh.getStatus(this.workflowId);
|
|
138
92
|
if (status <= 0) {
|
|
139
93
|
await complete();
|
|
@@ -10,10 +10,6 @@ export declare const Durable: {
|
|
|
10
10
|
Search: typeof Search;
|
|
11
11
|
Worker: typeof WorkerService;
|
|
12
12
|
workflow: typeof WorkflowService;
|
|
13
|
-
/**
|
|
14
|
-
* Shutdown everything. All connections, workers, and clients will be closed.
|
|
15
|
-
* Include in your signal handlers to ensure a clean shutdown.
|
|
16
|
-
*/
|
|
17
13
|
shutdown(): Promise<void>;
|
|
18
14
|
};
|
|
19
15
|
export type { ContextType };
|
|
@@ -13,10 +13,6 @@ exports.Durable = {
|
|
|
13
13
|
Search: search_1.Search,
|
|
14
14
|
Worker: worker_1.WorkerService,
|
|
15
15
|
workflow: workflow_1.WorkflowService,
|
|
16
|
-
/**
|
|
17
|
-
* Shutdown everything. All connections, workers, and clients will be closed.
|
|
18
|
-
* Include in your signal handlers to ensure a clean shutdown.
|
|
19
|
-
*/
|
|
20
16
|
async shutdown() {
|
|
21
17
|
await client_1.ClientService.shutdown();
|
|
22
18
|
await worker_1.WorkerService.shutdown();
|
|
@@ -1,33 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*********** HOTMESH 'DURABLE' MODULE APPLICATION GRAPH **********
|
|
3
|
-
*
|
|
4
|
-
* This HotMesh application spec uses 50 activities and 25 transitions
|
|
5
|
-
* to model and emulate the Temporal Application & Query servers using
|
|
6
|
-
* Redis as the backend.
|
|
7
|
-
*
|
|
8
|
-
* It's particularly useful for organizations with high-speed, high-volume
|
|
9
|
-
* use cases as it uses in-memory Redis Streams for transactional,
|
|
10
|
-
* workflow processing, while adhering to Temporal's developer-friendly syntax.
|
|
11
|
-
*
|
|
12
|
-
* This YAML file can also serve as a useful starting point for building
|
|
13
|
-
* Integration/BPM/Workflow servers in general (MuleSoft, etc) without the need
|
|
14
|
-
* for a physical application server.
|
|
15
|
-
*
|
|
16
|
-
* Possible use cases include:
|
|
17
|
-
* * Orchestration servers
|
|
18
|
-
* * Integration servers
|
|
19
|
-
* * BPMN engines
|
|
20
|
-
* * Reentrant process servers
|
|
21
|
-
* * Service Meshes
|
|
22
|
-
* * Master Data Management systems
|
|
23
|
-
*/
|
|
24
1
|
declare const APP_VERSION = "1";
|
|
25
2
|
declare const APP_ID = "durable";
|
|
26
|
-
/**
|
|
27
|
-
* returns a new durable workflow schema
|
|
28
|
-
* @param {string} app - app name (e.g., 'durable')
|
|
29
|
-
* @param {string} version - number as string (e.g., '1')
|
|
30
|
-
* @returns {string} HotMesh App YAML
|
|
31
|
-
*/
|
|
32
3
|
declare const getWorkflowYAML: (app: string, version: string) => string;
|
|
33
4
|
export { getWorkflowYAML, APP_VERSION, APP_ID, };
|
|
@@ -1,39 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
*********** HOTMESH 'DURABLE' MODULE APPLICATION GRAPH **********
|
|
4
|
-
*
|
|
5
|
-
* This HotMesh application spec uses 50 activities and 25 transitions
|
|
6
|
-
* to model and emulate the Temporal Application & Query servers using
|
|
7
|
-
* Redis as the backend.
|
|
8
|
-
*
|
|
9
|
-
* It's particularly useful for organizations with high-speed, high-volume
|
|
10
|
-
* use cases as it uses in-memory Redis Streams for transactional,
|
|
11
|
-
* workflow processing, while adhering to Temporal's developer-friendly syntax.
|
|
12
|
-
*
|
|
13
|
-
* This YAML file can also serve as a useful starting point for building
|
|
14
|
-
* Integration/BPM/Workflow servers in general (MuleSoft, etc) without the need
|
|
15
|
-
* for a physical application server.
|
|
16
|
-
*
|
|
17
|
-
* Possible use cases include:
|
|
18
|
-
* * Orchestration servers
|
|
19
|
-
* * Integration servers
|
|
20
|
-
* * BPMN engines
|
|
21
|
-
* * Reentrant process servers
|
|
22
|
-
* * Service Meshes
|
|
23
|
-
* * Master Data Management systems
|
|
24
|
-
*/
|
|
25
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
3
|
exports.APP_ID = exports.APP_VERSION = exports.getWorkflowYAML = void 0;
|
|
27
4
|
const APP_VERSION = '1';
|
|
28
5
|
exports.APP_VERSION = APP_VERSION;
|
|
29
6
|
const APP_ID = 'durable';
|
|
30
7
|
exports.APP_ID = APP_ID;
|
|
31
|
-
/**
|
|
32
|
-
* returns a new durable workflow schema
|
|
33
|
-
* @param {string} app - app name (e.g., 'durable')
|
|
34
|
-
* @param {string} version - number as string (e.g., '1')
|
|
35
|
-
* @returns {string} HotMesh App YAML
|
|
36
|
-
*/
|
|
37
8
|
const getWorkflowYAML = (app, version) => {
|
|
38
9
|
return `app:
|
|
39
10
|
id: ${app}
|
|
@@ -8,51 +8,16 @@ export declare class Search {
|
|
|
8
8
|
searchSessionIndex: number;
|
|
9
9
|
hotMeshClient: HotMesh;
|
|
10
10
|
store: StoreService<RedisClient, RedisMulti> | null;
|
|
11
|
+
cachedFields: Record<string, string>;
|
|
11
12
|
constructor(workflowId: string, hotMeshClient: HotMesh, searchSessionId: string);
|
|
12
13
|
safeKey(key: string): string;
|
|
13
|
-
/**
|
|
14
|
-
* For those deployments with a redis stack backend (with the FT module),
|
|
15
|
-
* this method will configure the search index for the workflow. For all
|
|
16
|
-
* others, this method will exit/fail gracefully and not index
|
|
17
|
-
* the fields in the HASH. However, all values are still available
|
|
18
|
-
* in the HASH.
|
|
19
|
-
*/
|
|
20
14
|
static configureSearchIndex(hotMeshClient: HotMesh, search?: WorkflowSearchOptions): Promise<void>;
|
|
21
|
-
/**
|
|
22
|
-
* For those deployments with a redis stack backend (with the FT module),
|
|
23
|
-
* this method will list all search indexes.
|
|
24
|
-
* @param {HotMesh} hotMeshClient - the hotmesh client
|
|
25
|
-
* @returns {Promise<string[]>} - the list of search indexes
|
|
26
|
-
*/
|
|
27
15
|
static listSearchIndexes(hotMeshClient: HotMesh): Promise<string[]>;
|
|
28
|
-
/**
|
|
29
|
-
* increments the index to return a unique search session guid when
|
|
30
|
-
* calling any method that produces side effects (changes the value)
|
|
31
|
-
*/
|
|
32
16
|
getSearchSessionGuid(): string;
|
|
33
|
-
/**
|
|
34
|
-
* Sets the fields listed in args. Returns the
|
|
35
|
-
* count of new fields that were set (does not
|
|
36
|
-
* count fields that were updated)
|
|
37
|
-
*/
|
|
38
17
|
set(...args: string[]): Promise<number>;
|
|
39
18
|
get(key: string): Promise<string>;
|
|
40
19
|
mget(...args: string[]): Promise<string[]>;
|
|
41
|
-
/**
|
|
42
|
-
* Deletes the fields listed in args. Returns the
|
|
43
|
-
* count of fields that were deleted.
|
|
44
|
-
*/
|
|
45
20
|
del(...args: string[]): Promise<number | void>;
|
|
46
|
-
/**
|
|
47
|
-
* Increments the value of a field by the given amount. Returns the
|
|
48
|
-
* new value of the field after the increment. Can be
|
|
49
|
-
* used to decrement the value of a field by specifying a negative.
|
|
50
|
-
*/
|
|
51
21
|
incr(key: string, val: number): Promise<number>;
|
|
52
|
-
/**
|
|
53
|
-
* Multiplies the value of a field by the given amount. Returns the
|
|
54
|
-
* new value of the field after the multiplication. NOTE:
|
|
55
|
-
* this is exponential multiplication.
|
|
56
|
-
*/
|
|
57
22
|
mult(key: string, val: number): Promise<number>;
|
|
58
23
|
}
|
|
@@ -6,6 +6,7 @@ const storage_1 = require("../../modules/storage");
|
|
|
6
6
|
class Search {
|
|
7
7
|
constructor(workflowId, hotMeshClient, searchSessionId) {
|
|
8
8
|
this.searchSessionIndex = 0;
|
|
9
|
+
this.cachedFields = {};
|
|
9
10
|
const keyParams = {
|
|
10
11
|
appId: hotMeshClient.appId,
|
|
11
12
|
jobId: workflowId
|
|
@@ -16,25 +17,30 @@ class Search {
|
|
|
16
17
|
this.store = hotMeshClient.engine.store;
|
|
17
18
|
}
|
|
18
19
|
safeKey(key) {
|
|
20
|
+
if (key.startsWith('"')) {
|
|
21
|
+
return key.slice(1, -1);
|
|
22
|
+
}
|
|
19
23
|
return `_${key}`;
|
|
20
24
|
}
|
|
21
|
-
/**
|
|
22
|
-
* For those deployments with a redis stack backend (with the FT module),
|
|
23
|
-
* this method will configure the search index for the workflow. For all
|
|
24
|
-
* others, this method will exit/fail gracefully and not index
|
|
25
|
-
* the fields in the HASH. However, all values are still available
|
|
26
|
-
* in the HASH.
|
|
27
|
-
*/
|
|
28
25
|
static async configureSearchIndex(hotMeshClient, search) {
|
|
29
26
|
if (search?.schema) {
|
|
30
27
|
const store = hotMeshClient.engine.store;
|
|
31
28
|
const schema = [];
|
|
32
29
|
for (const [key, value] of Object.entries(search.schema)) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
if (value.indexed !== false) {
|
|
31
|
+
schema.push(value.fieldName ? `${value.fieldName.toString()}` : `_${key}`);
|
|
32
|
+
schema.push(value.type ? value.type : 'TEXT');
|
|
33
|
+
if (value.noindex) {
|
|
34
|
+
schema.push('NOINDEX');
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
if (value.nostem && value.type === 'TEXT') {
|
|
38
|
+
schema.push('NOSTEM');
|
|
39
|
+
}
|
|
40
|
+
if (value.sortable) {
|
|
41
|
+
schema.push('SORTABLE');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
38
44
|
}
|
|
39
45
|
}
|
|
40
46
|
try {
|
|
@@ -51,12 +57,6 @@ class Search {
|
|
|
51
57
|
}
|
|
52
58
|
}
|
|
53
59
|
}
|
|
54
|
-
/**
|
|
55
|
-
* For those deployments with a redis stack backend (with the FT module),
|
|
56
|
-
* this method will list all search indexes.
|
|
57
|
-
* @param {HotMesh} hotMeshClient - the hotmesh client
|
|
58
|
-
* @returns {Promise<string[]>} - the list of search indexes
|
|
59
|
-
*/
|
|
60
60
|
static async listSearchIndexes(hotMeshClient) {
|
|
61
61
|
try {
|
|
62
62
|
const store = hotMeshClient.engine.store;
|
|
@@ -68,40 +68,36 @@ class Search {
|
|
|
68
68
|
return [];
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
-
/**
|
|
72
|
-
* increments the index to return a unique search session guid when
|
|
73
|
-
* calling any method that produces side effects (changes the value)
|
|
74
|
-
*/
|
|
75
71
|
getSearchSessionGuid() {
|
|
76
|
-
//return the search session as it would exist in the search session index
|
|
77
72
|
return `${this.searchSessionId}-${this.searchSessionIndex++}-`;
|
|
78
73
|
}
|
|
79
|
-
/**
|
|
80
|
-
* Sets the fields listed in args. Returns the
|
|
81
|
-
* count of new fields that were set (does not
|
|
82
|
-
* count fields that were updated)
|
|
83
|
-
*/
|
|
84
74
|
async set(...args) {
|
|
85
75
|
const ssGuid = this.getSearchSessionGuid();
|
|
86
76
|
const store = storage_1.asyncLocalStorage.getStore();
|
|
87
77
|
const replay = store?.get('replay') ?? {};
|
|
88
|
-
if (ssGuid in replay) {
|
|
89
|
-
return Number(replay[ssGuid]);
|
|
90
|
-
}
|
|
91
78
|
const safeArgs = [];
|
|
92
79
|
for (let i = 0; i < args.length; i += 2) {
|
|
93
|
-
const
|
|
80
|
+
const keyName = args[i];
|
|
81
|
+
delete this.cachedFields[keyName];
|
|
82
|
+
const key = this.safeKey(keyName);
|
|
94
83
|
const value = args[i + 1].toString();
|
|
95
84
|
safeArgs.push(key, value);
|
|
96
85
|
}
|
|
86
|
+
if (ssGuid in replay) {
|
|
87
|
+
return Number(replay[ssGuid]);
|
|
88
|
+
}
|
|
97
89
|
const fieldCount = await this.store.exec('HSET', this.jobId, ...safeArgs);
|
|
98
|
-
//no need to wait; set this interim value in the replay
|
|
99
90
|
this.store.exec('HSET', this.jobId, ssGuid, fieldCount.toString());
|
|
100
91
|
return Number(fieldCount);
|
|
101
92
|
}
|
|
102
93
|
async get(key) {
|
|
103
94
|
try {
|
|
104
|
-
|
|
95
|
+
if (key in this.cachedFields) {
|
|
96
|
+
return this.cachedFields[key];
|
|
97
|
+
}
|
|
98
|
+
const value = await this.store.exec('HGET', this.jobId, this.safeKey(key));
|
|
99
|
+
this.cachedFields[key] = value;
|
|
100
|
+
return value;
|
|
105
101
|
}
|
|
106
102
|
catch (error) {
|
|
107
103
|
this.hotMeshClient.logger.error('durable-search-get-error', { ...error });
|
|
@@ -109,45 +105,55 @@ class Search {
|
|
|
109
105
|
}
|
|
110
106
|
}
|
|
111
107
|
async mget(...args) {
|
|
108
|
+
let isCached = true;
|
|
109
|
+
const values = [];
|
|
112
110
|
const safeArgs = [];
|
|
113
111
|
for (let i = 0; i < args.length; i++) {
|
|
112
|
+
if (isCached && args[i] in this.cachedFields) {
|
|
113
|
+
values.push(this.cachedFields[args[i]]);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
isCached = false;
|
|
117
|
+
}
|
|
114
118
|
safeArgs.push(this.safeKey(args[i]));
|
|
115
119
|
}
|
|
116
120
|
try {
|
|
117
|
-
|
|
121
|
+
if (isCached) {
|
|
122
|
+
return values;
|
|
123
|
+
}
|
|
124
|
+
const returnValues = await this.store.exec('HMGET', this.jobId, ...safeArgs);
|
|
125
|
+
returnValues.forEach((value, index) => {
|
|
126
|
+
if (value !== null) {
|
|
127
|
+
this.cachedFields[args[index]] = value;
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
return returnValues;
|
|
118
131
|
}
|
|
119
132
|
catch (error) {
|
|
120
133
|
this.hotMeshClient.logger.error('durable-search-mget-error', { ...error });
|
|
121
134
|
return [];
|
|
122
135
|
}
|
|
123
136
|
}
|
|
124
|
-
/**
|
|
125
|
-
* Deletes the fields listed in args. Returns the
|
|
126
|
-
* count of fields that were deleted.
|
|
127
|
-
*/
|
|
128
137
|
async del(...args) {
|
|
129
138
|
const ssGuid = this.getSearchSessionGuid();
|
|
130
139
|
const store = storage_1.asyncLocalStorage.getStore();
|
|
131
140
|
const replay = store?.get('replay') ?? {};
|
|
132
|
-
if (ssGuid in replay) {
|
|
133
|
-
return Number(replay[ssGuid]);
|
|
134
|
-
}
|
|
135
141
|
const safeArgs = [];
|
|
136
142
|
for (let i = 0; i < args.length; i++) {
|
|
137
|
-
|
|
143
|
+
const keyName = args[i];
|
|
144
|
+
delete this.cachedFields[keyName];
|
|
145
|
+
safeArgs.push(this.safeKey(keyName));
|
|
146
|
+
}
|
|
147
|
+
if (ssGuid in replay) {
|
|
148
|
+
return Number(replay[ssGuid]);
|
|
138
149
|
}
|
|
139
150
|
const response = await this.store.exec('HDEL', this.jobId, ...safeArgs);
|
|
140
151
|
const formattedResponse = isNaN(response) ? 0 : Number(response);
|
|
141
|
-
//no need to wait; set this interim value in the replay
|
|
142
152
|
this.store.exec('HSET', this.jobId, ssGuid, formattedResponse.toString());
|
|
143
153
|
return formattedResponse;
|
|
144
154
|
}
|
|
145
|
-
/**
|
|
146
|
-
* Increments the value of a field by the given amount. Returns the
|
|
147
|
-
* new value of the field after the increment. Can be
|
|
148
|
-
* used to decrement the value of a field by specifying a negative.
|
|
149
|
-
*/
|
|
150
155
|
async incr(key, val) {
|
|
156
|
+
delete this.cachedFields[key];
|
|
151
157
|
const ssGuid = this.getSearchSessionGuid();
|
|
152
158
|
const store = storage_1.asyncLocalStorage.getStore();
|
|
153
159
|
const replay = store?.get('replay') ?? {};
|
|
@@ -155,16 +161,11 @@ class Search {
|
|
|
155
161
|
return Number(replay[ssGuid]);
|
|
156
162
|
}
|
|
157
163
|
const num = await this.store.exec('HINCRBYFLOAT', this.jobId, this.safeKey(key), val.toString());
|
|
158
|
-
//no need to wait; set this interim value in the replay
|
|
159
164
|
this.store.exec('HSET', this.jobId, ssGuid, num.toString());
|
|
160
165
|
return Number(num);
|
|
161
166
|
}
|
|
162
|
-
/**
|
|
163
|
-
* Multiplies the value of a field by the given amount. Returns the
|
|
164
|
-
* new value of the field after the multiplication. NOTE:
|
|
165
|
-
* this is exponential multiplication.
|
|
166
|
-
*/
|
|
167
167
|
async mult(key, val) {
|
|
168
|
+
delete this.cachedFields[key];
|
|
168
169
|
const ssGuid = this.getSearchSessionGuid();
|
|
169
170
|
const store = storage_1.asyncLocalStorage.getStore();
|
|
170
171
|
const replay = store?.get('replay') ?? {};
|
|
@@ -175,7 +176,6 @@ class Search {
|
|
|
175
176
|
if (ssGuidValue === 1) {
|
|
176
177
|
const log = Math.log(val);
|
|
177
178
|
const logTotal = await this.store.exec('HINCRBYFLOAT', this.jobId, this.safeKey(key), log.toString());
|
|
178
|
-
//no need to wait; set this interim value in the replay
|
|
179
179
|
this.store.exec('HSET', this.jobId, ssGuid, logTotal.toString());
|
|
180
180
|
return Math.exp(Number(logTotal));
|
|
181
181
|
}
|