@hotmeshio/hotmesh 0.0.60 → 0.1.0
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.d.ts +1 -1
- package/build/modules/enums.js +10 -2
- package/build/modules/errors.d.ts +3 -3
- package/build/modules/errors.js +8 -8
- package/build/modules/key.d.ts +1 -1
- package/build/modules/key.js +3 -3
- package/build/modules/utils.d.ts +5 -5
- package/build/modules/utils.js +20 -16
- package/build/package.json +41 -38
- package/build/services/activities/activity.js +37 -20
- package/build/services/activities/await.d.ts +1 -1
- package/build/services/activities/await.js +15 -7
- package/build/services/activities/cycle.d.ts +1 -1
- package/build/services/activities/cycle.js +16 -8
- package/build/services/activities/hook.d.ts +1 -1
- package/build/services/activities/hook.js +8 -4
- package/build/services/activities/interrupt.d.ts +1 -1
- package/build/services/activities/interrupt.js +14 -6
- package/build/services/activities/signal.d.ts +1 -1
- package/build/services/activities/signal.js +12 -4
- package/build/services/activities/trigger.d.ts +1 -1
- package/build/services/activities/trigger.js +19 -12
- package/build/services/activities/worker.d.ts +1 -1
- package/build/services/activities/worker.js +15 -7
- package/build/services/collator/index.js +12 -12
- package/build/services/compiler/deployer.js +17 -12
- package/build/services/compiler/index.js +4 -4
- package/build/services/compiler/validator.d.ts +3 -3
- package/build/services/compiler/validator.js +12 -3
- package/build/services/durable/client.d.ts +1 -1
- package/build/services/durable/client.js +18 -12
- package/build/services/durable/connection.d.ts +1 -1
- package/build/services/durable/exporter.d.ts +1 -1
- package/build/services/durable/exporter.js +3 -4
- package/build/services/durable/handle.d.ts +1 -1
- package/build/services/durable/handle.js +4 -1
- package/build/services/durable/index.d.ts +1 -1
- package/build/services/durable/index.js +2 -2
- package/build/services/durable/schemas/factory.d.ts +1 -1
- package/build/services/durable/search.js +19 -11
- package/build/services/durable/worker.js +50 -30
- package/build/services/durable/workflow.d.ts +5 -5
- package/build/services/durable/workflow.js +34 -18
- package/build/services/engine/index.js +33 -26
- package/build/services/exporter/index.d.ts +1 -1
- package/build/services/exporter/index.js +3 -3
- package/build/services/hotmesh/index.js +1 -1
- package/build/services/logger/index.js +1 -1
- package/build/services/mapper/index.js +3 -1
- package/build/services/pipe/functions/date.js +1 -1
- package/build/services/pipe/index.js +37 -10
- package/build/services/quorum/index.js +14 -11
- package/build/services/reporter/index.js +15 -12
- package/build/services/router/index.d.ts +2 -2
- package/build/services/router/index.js +73 -23
- package/build/services/serializer/index.js +48 -26
- package/build/services/store/cache.d.ts +5 -5
- package/build/services/store/cache.js +2 -2
- package/build/services/store/clients/ioredis.js +3 -3
- package/build/services/store/clients/redis.js +24 -4
- package/build/services/store/index.d.ts +9 -3
- package/build/services/store/index.js +122 -60
- package/build/services/stream/clients/ioredis.js +4 -4
- package/build/services/stream/clients/redis.js +31 -4
- package/build/services/task/index.js +8 -11
- package/build/services/telemetry/index.js +21 -14
- package/build/services/worker/index.d.ts +6 -6
- package/build/services/worker/index.js +12 -7
- package/build/types/activity.d.ts +3 -3
- package/build/types/exporter.d.ts +2 -2
- package/build/types/exporter.js +0 -6
- package/build/types/hook.d.ts +1 -1
- package/build/types/hotmesh.js +0 -1
- package/build/types/index.d.ts +12 -12
- package/build/types/job.d.ts +1 -1
- package/build/types/logger.js +0 -1
- package/build/types/quorum.d.ts +1 -1
- package/build/types/stats.d.ts +1 -1
- package/build/types/stream.d.ts +1 -2
- package/build/types/telemetry.d.ts +1 -1
- package/build/types/transition.d.ts +1 -1
- package/package.json +41 -38
- package/types/activity.ts +56 -39
- package/types/async.ts +2 -3
- package/types/collator.ts +5 -5
- package/types/durable.ts +161 -161
- package/types/error.ts +37 -37
- package/types/exporter.ts +14 -9
- package/types/hook.ts +11 -4
- package/types/hotmesh.ts +26 -25
- package/types/index.ts +53 -53
- package/types/job.ts +33 -33
- package/types/logger.ts +1 -1
- package/types/map.ts +1 -1
- package/types/pipe.ts +10 -8
- package/types/quorum.ts +20 -13
- package/types/redis.ts +70 -15
- package/types/serializer.ts +8 -6
- package/types/stats.ts +22 -6
- package/types/stream.ts +9 -9
- package/types/task.ts +7 -1
- package/types/telemetry.ts +2 -1
- package/types/transition.ts +8 -8
package/README.md
CHANGED
package/build/modules/enums.d.ts
CHANGED
package/build/modules/enums.js
CHANGED
|
@@ -40,7 +40,11 @@ exports.HMSH_DURABLE_MAX_INTERVAL = '120s';
|
|
|
40
40
|
exports.HMSH_DURABLE_EXP_BACKOFF = 10;
|
|
41
41
|
const BASE_BLOCK_DURATION = 10000;
|
|
42
42
|
const TEST_BLOCK_DURATION = 1000;
|
|
43
|
-
exports.HMSH_BLOCK_TIME_MS = process.env.HMSH_BLOCK_TIME_MS
|
|
43
|
+
exports.HMSH_BLOCK_TIME_MS = process.env.HMSH_BLOCK_TIME_MS
|
|
44
|
+
? parseInt(process.env.HMSH_BLOCK_TIME_MS, 10)
|
|
45
|
+
: process.env.NODE_ENV === 'test'
|
|
46
|
+
? TEST_BLOCK_DURATION
|
|
47
|
+
: BASE_BLOCK_DURATION;
|
|
44
48
|
exports.HMSH_XCLAIM_DELAY_MS = parseInt(process.env.HMSH_XCLAIM_DELAY_MS, 10) || 1000 * 60;
|
|
45
49
|
exports.HMSH_XCLAIM_COUNT = parseInt(process.env.HMSH_XCLAIM_COUNT, 10) || 3;
|
|
46
50
|
exports.HMSH_XPENDING_COUNT = parseInt(process.env.HMSH_XPENDING_COUNT, 10) || 10;
|
|
@@ -48,7 +52,11 @@ exports.HMSH_XPENDING_COUNT = parseInt(process.env.HMSH_XPENDING_COUNT, 10) || 1
|
|
|
48
52
|
exports.HMSH_EXPIRE_DURATION = parseInt(process.env.HMSH_EXPIRE_DURATION, 10) || 1;
|
|
49
53
|
const BASE_FIDELITY_SECONDS = 5;
|
|
50
54
|
const TEST_FIDELITY_SECONDS = 1;
|
|
51
|
-
exports.HMSH_FIDELITY_SECONDS = process.env.HMSH_FIDELITY_SECONDS
|
|
55
|
+
exports.HMSH_FIDELITY_SECONDS = process.env.HMSH_FIDELITY_SECONDS
|
|
56
|
+
? parseInt(process.env.HMSH_FIDELITY_SECONDS, 10)
|
|
57
|
+
: process.env.NODE_ENV === 'test'
|
|
58
|
+
? TEST_FIDELITY_SECONDS
|
|
59
|
+
: BASE_FIDELITY_SECONDS;
|
|
52
60
|
exports.HMSH_SCOUT_INTERVAL_SECONDS = parseInt(process.env.HMSH_SCOUT_INTERVAL_SECONDS, 10) || 60;
|
|
53
61
|
// UTILS
|
|
54
62
|
exports.HMSH_GUID_SIZE = Math.min(parseInt(process.env.HMSH_GUID_SIZE, 10) || 22, 32);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ActivityDuplex } from
|
|
2
|
-
import { CollationFaultType, CollationStage } from
|
|
3
|
-
import { DurableChildErrorType, DurableProxyErrorType, DurableSleepErrorType, DurableWaitForAllErrorType, DurableWaitForErrorType } from
|
|
1
|
+
import { ActivityDuplex } from '../types/activity';
|
|
2
|
+
import { CollationFaultType, CollationStage } from '../types/collator';
|
|
3
|
+
import { DurableChildErrorType, DurableProxyErrorType, DurableSleepErrorType, DurableWaitForAllErrorType, DurableWaitForErrorType } from '../types/error';
|
|
4
4
|
declare class GetStateError extends Error {
|
|
5
5
|
jobId: string;
|
|
6
6
|
code: number;
|
package/build/modules/errors.js
CHANGED
|
@@ -12,7 +12,7 @@ class GetStateError extends Error {
|
|
|
12
12
|
exports.GetStateError = GetStateError;
|
|
13
13
|
class SetStateError extends Error {
|
|
14
14
|
constructor() {
|
|
15
|
-
super(
|
|
15
|
+
super('Error occurred while setting job state');
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
exports.SetStateError = SetStateError;
|
|
@@ -130,19 +130,19 @@ class DurableRetryError extends Error {
|
|
|
130
130
|
exports.DurableRetryError = DurableRetryError;
|
|
131
131
|
class MapDataError extends Error {
|
|
132
132
|
constructor() {
|
|
133
|
-
super(
|
|
133
|
+
super('Error occurred while mapping data');
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
exports.MapDataError = MapDataError;
|
|
137
137
|
class RegisterTimeoutError extends Error {
|
|
138
138
|
constructor() {
|
|
139
|
-
super(
|
|
139
|
+
super('Error occurred while registering activity timeout');
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
exports.RegisterTimeoutError = RegisterTimeoutError;
|
|
143
143
|
class DuplicateJobError extends Error {
|
|
144
144
|
constructor(jobId) {
|
|
145
|
-
super(
|
|
145
|
+
super('Duplicate job');
|
|
146
146
|
this.jobId = jobId;
|
|
147
147
|
this.message = `Duplicate job: ${jobId}`;
|
|
148
148
|
}
|
|
@@ -150,7 +150,7 @@ class DuplicateJobError extends Error {
|
|
|
150
150
|
exports.DuplicateJobError = DuplicateJobError;
|
|
151
151
|
class InactiveJobError extends Error {
|
|
152
152
|
constructor(jobId, status, activityId) {
|
|
153
|
-
super(
|
|
153
|
+
super('Inactive job');
|
|
154
154
|
this.jobId = jobId;
|
|
155
155
|
this.activityId = activityId;
|
|
156
156
|
this.message = `Inactive job: ${jobId}`;
|
|
@@ -160,7 +160,7 @@ class InactiveJobError extends Error {
|
|
|
160
160
|
exports.InactiveJobError = InactiveJobError;
|
|
161
161
|
class GenerationalError extends Error {
|
|
162
162
|
constructor(expected, actual, jobId, activityId, dimensionalAddress) {
|
|
163
|
-
super(
|
|
163
|
+
super('Generational Error');
|
|
164
164
|
this.expected = expected;
|
|
165
165
|
this.actual = actual;
|
|
166
166
|
this.jobId = jobId;
|
|
@@ -171,13 +171,13 @@ class GenerationalError extends Error {
|
|
|
171
171
|
exports.GenerationalError = GenerationalError;
|
|
172
172
|
class ExecActivityError extends Error {
|
|
173
173
|
constructor() {
|
|
174
|
-
super(
|
|
174
|
+
super('Error occurred while executing activity');
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
177
|
exports.ExecActivityError = ExecActivityError;
|
|
178
178
|
class CollationError extends Error {
|
|
179
179
|
constructor(status, leg, stage, fault) {
|
|
180
|
-
super(
|
|
180
|
+
super('collation-error');
|
|
181
181
|
this.leg = leg;
|
|
182
182
|
this.status = status;
|
|
183
183
|
this.stage = stage;
|
package/build/modules/key.d.ts
CHANGED
|
@@ -45,4 +45,4 @@ declare class KeyService {
|
|
|
45
45
|
*/
|
|
46
46
|
static mintKey(namespace: string, keyType: KeyType, params: KeyStoreParams): string;
|
|
47
47
|
}
|
|
48
|
-
export { KeyService, KeyType, KeyStoreParams, HMNS, KEYSEP, TYPSEP, WEBSEP, VALSEP };
|
|
48
|
+
export { KeyService, KeyType, KeyStoreParams, HMNS, KEYSEP, TYPSEP, WEBSEP, VALSEP, };
|
package/build/modules/key.js
CHANGED
|
@@ -30,9 +30,9 @@ Object.defineProperty(exports, "KeyType", { enumerable: true, get: function () {
|
|
|
30
30
|
* hmsh:<appid>:sym:keys:<activityid|$subscribes> -> {hash} list of symbols based upon schema enums (initially) and adaptively optimized (later) during runtime; if '$subscribes' is used as the activityid, it is a top-level `job` symbol set (for job keys)
|
|
31
31
|
* hmsh:<appid>:sym:vals: -> {hash} list of symbols for job values across all app versions
|
|
32
32
|
*/
|
|
33
|
-
const HMNS =
|
|
33
|
+
const HMNS = 'hmsh';
|
|
34
34
|
exports.HMNS = HMNS;
|
|
35
|
-
const KEYSEP = ':'; //default delimiter for keys
|
|
35
|
+
const KEYSEP = ':'; //default delimiter for keys
|
|
36
36
|
exports.KEYSEP = KEYSEP;
|
|
37
37
|
const VALSEP = '::'; //default delimiter for vals
|
|
38
38
|
exports.VALSEP = VALSEP;
|
|
@@ -97,7 +97,7 @@ class KeyService {
|
|
|
97
97
|
case hotmesh_1.KeyType.STREAMS:
|
|
98
98
|
return `${namespace}:${params.appId || ''}:x:${params.topic || ''}`;
|
|
99
99
|
default:
|
|
100
|
-
throw new Error(
|
|
100
|
+
throw new Error('Invalid key type.');
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
}
|
package/build/modules/utils.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { StoreService } from
|
|
3
|
-
import { AppSubscriptions, AppTransitions, AppVID } from
|
|
4
|
-
import { RedisClient, RedisMulti } from
|
|
5
|
-
import { StringAnyType } from
|
|
6
|
-
import { StreamCode, StreamStatus } from
|
|
2
|
+
import { StoreService } from '../services/store';
|
|
3
|
+
import { AppSubscriptions, AppTransitions, AppVID } from '../types/app';
|
|
4
|
+
import { RedisClient, RedisMulti } from '../types/redis';
|
|
5
|
+
import { StringAnyType } from '../types/serializer';
|
|
6
|
+
import { StreamCode, StreamStatus } from '../types/stream';
|
|
7
7
|
import { SystemHealth } from '../types/quorum';
|
|
8
8
|
export declare function getSystemHealth(): Promise<SystemHealth>;
|
|
9
9
|
export declare function sleepFor(ms: number): Promise<unknown>;
|
package/build/modules/utils.js
CHANGED
|
@@ -50,33 +50,33 @@ function sleepImmediate() {
|
|
|
50
50
|
return new Promise((resolve) => setImmediate(resolve));
|
|
51
51
|
}
|
|
52
52
|
exports.sleepImmediate = sleepImmediate;
|
|
53
|
-
function s4() {
|
|
54
|
-
return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
|
|
55
|
-
}
|
|
56
53
|
function guid(size = enums_1.HMSH_GUID_SIZE) {
|
|
57
|
-
return
|
|
54
|
+
return `H` + (0, nanoid_1.nanoid)(size);
|
|
58
55
|
}
|
|
59
56
|
exports.guid = guid;
|
|
60
57
|
function deterministicRandom(seed) {
|
|
61
|
-
|
|
58
|
+
const x = Math.sin(seed) * 10000;
|
|
62
59
|
return x - Math.floor(x);
|
|
63
60
|
}
|
|
64
61
|
exports.deterministicRandom = deterministicRandom;
|
|
65
62
|
function identifyRedisType(redisInstance) {
|
|
66
63
|
const prototype = Object.getPrototypeOf(redisInstance);
|
|
67
|
-
if ('defineCommand' in prototype ||
|
|
64
|
+
if ('defineCommand' in prototype ||
|
|
65
|
+
Object.keys(prototype).includes('multi')) {
|
|
68
66
|
return 'ioredis';
|
|
69
67
|
}
|
|
70
68
|
else if (Object.keys(prototype).includes('Multi')) {
|
|
71
69
|
return 'redis';
|
|
72
70
|
}
|
|
73
71
|
if (redisInstance.constructor) {
|
|
74
|
-
if (redisInstance.constructor.name === 'Redis' ||
|
|
72
|
+
if (redisInstance.constructor.name === 'Redis' ||
|
|
73
|
+
redisInstance.constructor.name === 'EventEmitter') {
|
|
75
74
|
if ('hset' in redisInstance) {
|
|
76
75
|
return 'ioredis';
|
|
77
76
|
}
|
|
78
77
|
}
|
|
79
|
-
else if (redisInstance.constructor.name === 'RedisClient' ||
|
|
78
|
+
else if (redisInstance.constructor.name === 'RedisClient' ||
|
|
79
|
+
redisInstance.constructor.name === 'Commander') {
|
|
80
80
|
if ('HSET' in redisInstance) {
|
|
81
81
|
return 'redis';
|
|
82
82
|
}
|
|
@@ -92,10 +92,11 @@ exports.polyfill = {
|
|
|
92
92
|
return 'hook';
|
|
93
93
|
}
|
|
94
94
|
return activityType;
|
|
95
|
-
}
|
|
95
|
+
},
|
|
96
96
|
};
|
|
97
97
|
function identifyRedisTypeFromClass(redisClass) {
|
|
98
|
-
if (redisClass && redisClass.name === 'Redis' ||
|
|
98
|
+
if (redisClass && redisClass.name === 'Redis' ||
|
|
99
|
+
redisClass.name === 'EventEmitter') {
|
|
99
100
|
return 'ioredis';
|
|
100
101
|
}
|
|
101
102
|
else if (redisClass && 'createClient' in redisClass) {
|
|
@@ -107,7 +108,7 @@ exports.identifyRedisTypeFromClass = identifyRedisTypeFromClass;
|
|
|
107
108
|
function matchesStatusCode(code, pattern) {
|
|
108
109
|
if (typeof pattern === 'string') {
|
|
109
110
|
// Convert '*' wildcard to its regex equivalent (\d)
|
|
110
|
-
const regexPattern = `^${pattern.replace(/\*/g,
|
|
111
|
+
const regexPattern = `^${pattern.replace(/\*/g, '\\d')}$`;
|
|
111
112
|
return new RegExp(regexPattern).test(code.toString());
|
|
112
113
|
}
|
|
113
114
|
return pattern.test(code.toString());
|
|
@@ -120,7 +121,7 @@ exports.matchesStatus = matchesStatus;
|
|
|
120
121
|
function XSleepFor(ms) {
|
|
121
122
|
//can be interrupted with `clearTimeout`
|
|
122
123
|
let timerId;
|
|
123
|
-
|
|
124
|
+
const promise = new Promise((resolve) => {
|
|
124
125
|
timerId = setTimeout(resolve, ms);
|
|
125
126
|
});
|
|
126
127
|
return { promise, timerId };
|
|
@@ -175,7 +176,10 @@ function getTimeSeries(granularity) {
|
|
|
175
176
|
else if (granularityUnit === 'h') {
|
|
176
177
|
now.setUTCMinutes(0, 0, 0);
|
|
177
178
|
}
|
|
178
|
-
return now
|
|
179
|
+
return now
|
|
180
|
+
.toISOString()
|
|
181
|
+
.replace(/:\d\d\..+|-|T/g, '')
|
|
182
|
+
.replace(':', '');
|
|
179
183
|
}
|
|
180
184
|
exports.getTimeSeries = getTimeSeries;
|
|
181
185
|
function formatISODate(input) {
|
|
@@ -189,8 +193,8 @@ function getSymKey(number) {
|
|
|
189
193
|
if (number < 0 || number >= Math.pow(base, 3)) {
|
|
190
194
|
throw new Error('Number out of range');
|
|
191
195
|
}
|
|
192
|
-
|
|
193
|
-
|
|
196
|
+
const [q1, r1] = divmod(number, base);
|
|
197
|
+
const [q2, r2] = divmod(q1, base);
|
|
194
198
|
return alphabet[q2] + alphabet[r1] + alphabet[r2];
|
|
195
199
|
}
|
|
196
200
|
exports.getSymKey = getSymKey;
|
|
@@ -200,7 +204,7 @@ function getSymVal(number) {
|
|
|
200
204
|
if (number < 0 || number >= Math.pow(base, 2)) {
|
|
201
205
|
throw new Error('Number out of range');
|
|
202
206
|
}
|
|
203
|
-
|
|
207
|
+
const [q, r] = divmod(number, base);
|
|
204
208
|
return alphabet[q] + alphabet[r];
|
|
205
209
|
}
|
|
206
210
|
exports.getSymVal = getSymVal;
|
package/build/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hotmeshio/hotmesh",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Unbreakable Workflows",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -13,63 +13,63 @@
|
|
|
13
13
|
"access": "public"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
|
-
"clean": "rimraf ./build",
|
|
17
16
|
"build": "tsc --build tsconfig.json",
|
|
17
|
+
"clean": "rimraf ./build",
|
|
18
18
|
"clean-build": "npm run clean && npm run build",
|
|
19
19
|
"lint": "eslint . --ext .ts",
|
|
20
20
|
"lint:fix": "eslint . --fix --ext .ts",
|
|
21
21
|
"start": "ts-node src/index.ts",
|
|
22
22
|
"test": "NODE_ENV=test jest --detectOpenHandles --forceExit --verbose",
|
|
23
|
-
"test:
|
|
24
|
-
"test:unit": "NODE_ENV=test jest ./tests/unit/*/*/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
25
|
-
"test:pipe": "NODE_ENV=test jest ./tests/unit/services/pipe/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
23
|
+
"test:await": "NODE_ENV=test jest ./tests/functional/awaiter/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
26
24
|
"test:compile": "NODE_ENV=test jest ./tests/functional/compile/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
27
|
-
"test:cycle": "NODE_ENV=test jest ./tests/functional/cycle/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
28
|
-
"test:trigger": "NODE_ENV=test jest ./tests/unit/services/activities/trigger.test.ts --detectOpenHandles --forceExit --verbose",
|
|
29
25
|
"test:connect": "NODE_ENV=test jest ./tests/unit/services/connector/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
30
|
-
"test:connect:redis": "NODE_ENV=test jest ./tests/unit/services/connector/clients/redis.test.ts --detectOpenHandles --forceExit --verbose",
|
|
31
26
|
"test:connect:ioredis": "NODE_ENV=test jest ./tests/unit/services/connector/clients/ioredis.test.ts --detectOpenHandles --forceExit --verbose",
|
|
32
|
-
"test:
|
|
27
|
+
"test:connect:redis": "NODE_ENV=test jest ./tests/unit/services/connector/clients/redis.test.ts --detectOpenHandles --forceExit --verbose",
|
|
28
|
+
"test:cycle": "NODE_ENV=test jest ./tests/functional/cycle/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
29
|
+
"test:durable": "NODE_ENV=test jest ./tests/durable/*/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
30
|
+
"test:durable:basic": "NODE_ENV=test jest ./tests/durable/basic/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
31
|
+
"test:durable:collision": "NODE_ENV=test jest ./tests/durable/collision/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
32
|
+
"test:durable:fatal": "NODE_ENV=test jest ./tests/durable/fatal/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
33
|
+
"test:durable:goodbye": "NODE_ENV=test jest ./tests/durable/goodbye/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
34
|
+
"test:durable:hello": "NODE_ENV=test jest ./tests/durable/helloworld/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
35
|
+
"test:durable:hook": "NODE_ENV=test jest ./tests/durable/hook/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
36
|
+
"test:durable:interrupt": "NODE_ENV=test jest ./tests/durable/interrupt/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
37
|
+
"test:durable:loopactivity": "NODE_ENV=test jest ./tests/durable/loopactivity/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
38
|
+
"test:durable:nested": "NODE_ENV=test jest ./tests/durable/nested/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
39
|
+
"test:durable:retry": "NODE_ENV=test jest ./tests/durable/retry/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
40
|
+
"test:durable:sleep": "NODE_ENV=test jest ./tests/durable/sleep/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
41
|
+
"test:durable:signal": "NODE_ENV=test jest ./tests/durable/signal/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
42
|
+
"test:durable:unknown": "NODE_ENV=test jest ./tests/durable/unknown/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
33
43
|
"test:emit": "NODE_ENV=test jest ./tests/functional/emit/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
34
|
-
"test:
|
|
35
|
-
"test:
|
|
44
|
+
"test:functional": "NODE_ENV=test jest ./tests/functional/*/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
45
|
+
"test:hmsh": "NODE_ENV=test jest ./tests/functional/index.test.ts --detectOpenHandles --verbose",
|
|
36
46
|
"test:hook": "NODE_ENV=test jest ./tests/functional/hook/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
37
|
-
"test:signal": "NODE_ENV=test jest ./tests/functional/signal/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
38
47
|
"test:interrupt": "NODE_ENV=test jest ./tests/functional/interrupt/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
39
48
|
"test:parallel": "NODE_ENV=test jest ./tests/functional/parallel/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
40
|
-
"test:
|
|
49
|
+
"test:pipe": "NODE_ENV=test jest ./tests/unit/services/pipe/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
41
50
|
"test:quorum": "NODE_ENV=test jest ./tests/functional/quorum/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
42
51
|
"test:reclaim": "NODE_ENV=test jest ./tests/functional/reclaim/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
43
52
|
"test:redeploy": "NODE_ENV=test jest ./tests/functional/redeploy/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
53
|
+
"test:reentrant": "NODE_ENV=test jest ./tests/functional/reentrant/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
44
54
|
"test:retry": "NODE_ENV=test jest ./tests/functional/retry/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
55
|
+
"test:sequence": "NODE_ENV=test jest ./tests/functional/sequence/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
56
|
+
"test:signal": "NODE_ENV=test jest ./tests/functional/signal/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
45
57
|
"test:status": "NODE_ENV=test jest ./tests/functional/status/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
46
|
-
"test:store:redis": "NODE_ENV=test jest ./tests/functional/store/clients/redis.test.ts --detectOpenHandles --forceExit --verbose",
|
|
47
58
|
"test:store:ioredis": "NODE_ENV=test jest ./tests/functional/store/clients/ioredis.test.ts --detectOpenHandles --forceExit --verbose",
|
|
48
|
-
"test:
|
|
59
|
+
"test:store:redis": "NODE_ENV=test jest ./tests/functional/store/clients/redis.test.ts --detectOpenHandles --forceExit --verbose",
|
|
49
60
|
"test:stream:ioredis": "NODE_ENV=test jest ./tests/functional/stream/clients/ioredis.test.ts --detectOpenHandles --forceExit --verbose",
|
|
50
|
-
"test:
|
|
61
|
+
"test:stream:redis": "NODE_ENV=test jest ./tests/functional/stream/clients/redis.test.ts --detectOpenHandles --forceExit --verbose",
|
|
51
62
|
"test:sub:ioredis": "NODE_ENV=test jest ./tests/functional/sub/clients/ioredis.test.ts --detectOpenHandles --forceExit --verbose",
|
|
52
|
-
"test:
|
|
53
|
-
"test:
|
|
54
|
-
"test:
|
|
55
|
-
"test:durable:hello": "NODE_ENV=test jest ./tests/durable/helloworld/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
56
|
-
"test:durable:interrupt": "NODE_ENV=test jest ./tests/durable/interrupt/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
57
|
-
"test:durable:goodbye": "NODE_ENV=test jest ./tests/durable/goodbye/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
58
|
-
"test:durable:hook": "NODE_ENV=test jest ./tests/durable/hook/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
59
|
-
"test:durable:retry": "NODE_ENV=test jest ./tests/durable/retry/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
60
|
-
"test:durable:fatal": "NODE_ENV=test jest ./tests/durable/fatal/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
61
|
-
"test:durable:unknown": "NODE_ENV=test jest ./tests/durable/unknown/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
62
|
-
"test:durable:sleep": "NODE_ENV=test jest ./tests/durable/sleep/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
63
|
-
"test:durable:signal": "NODE_ENV=test jest ./tests/durable/signal/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
64
|
-
"test:durable:loopactivity": "NODE_ENV=test jest ./tests/durable/loopactivity/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
65
|
-
"test:durable:nested": "NODE_ENV=test jest ./tests/durable/nested/index.test.ts --detectOpenHandles --forceExit --verbose"
|
|
63
|
+
"test:sub:redis": "NODE_ENV=test jest ./tests/functional/sub/clients/redis.test.ts --detectOpenHandles --forceExit --verbose",
|
|
64
|
+
"test:trigger": "NODE_ENV=test jest ./tests/unit/services/activities/trigger.test.ts --detectOpenHandles --forceExit --verbose",
|
|
65
|
+
"test:unit": "NODE_ENV=test jest ./tests/unit/*/*/index.test.ts --detectOpenHandles --forceExit --verbose"
|
|
66
66
|
},
|
|
67
67
|
"keywords": [
|
|
68
|
+
"workflow",
|
|
68
69
|
"durable workflow",
|
|
69
|
-
"HotMesh",
|
|
70
|
-
"service mesh",
|
|
71
|
-
"workflows",
|
|
72
70
|
"operational data",
|
|
71
|
+
"service mesh",
|
|
72
|
+
"HotMesh",
|
|
73
73
|
"Redis",
|
|
74
74
|
"OLAP",
|
|
75
75
|
"OLTP",
|
|
@@ -89,9 +89,12 @@
|
|
|
89
89
|
"devDependencies": {
|
|
90
90
|
"@types/jest": "^29.5.0",
|
|
91
91
|
"@types/node": "^18.15.11",
|
|
92
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
93
|
-
"@typescript-eslint/parser": "^5.
|
|
94
|
-
"eslint": "^8.
|
|
92
|
+
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
93
|
+
"@typescript-eslint/parser": "^5.62.0",
|
|
94
|
+
"eslint": "^8.57.0",
|
|
95
|
+
"eslint-config-prettier": "^9.1.0",
|
|
96
|
+
"eslint-plugin-import": "^2.29.1",
|
|
97
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
95
98
|
"ioredis": "^5.3.2",
|
|
96
99
|
"jest": "^29.5.0",
|
|
97
100
|
"redis": "^4.6.13",
|
|
@@ -102,7 +105,7 @@
|
|
|
102
105
|
"typescript": "^5.0.4"
|
|
103
106
|
},
|
|
104
107
|
"peerDependencies": {
|
|
105
|
-
"
|
|
106
|
-
"
|
|
108
|
+
"ioredis": "^4.0.0 || ^5.0.0",
|
|
109
|
+
"redis": "^4.0.0"
|
|
107
110
|
}
|
|
108
111
|
}
|
|
@@ -56,13 +56,21 @@ class Activity {
|
|
|
56
56
|
this.setLeg(2);
|
|
57
57
|
const jid = this.context.metadata.jid;
|
|
58
58
|
if (!jid) {
|
|
59
|
-
this.logger.error('activity-process-event-error', {
|
|
59
|
+
this.logger.error('activity-process-event-error', {
|
|
60
|
+
message: 'job id is undefined',
|
|
61
|
+
});
|
|
60
62
|
return;
|
|
61
63
|
}
|
|
62
64
|
const aid = this.metadata.aid;
|
|
63
65
|
this.status = status;
|
|
64
66
|
this.code = code;
|
|
65
|
-
this.logger.debug('activity-process-event', {
|
|
67
|
+
this.logger.debug('activity-process-event', {
|
|
68
|
+
topic: this.config.subtype,
|
|
69
|
+
jid,
|
|
70
|
+
aid,
|
|
71
|
+
status,
|
|
72
|
+
code,
|
|
73
|
+
});
|
|
66
74
|
let telemetry;
|
|
67
75
|
try {
|
|
68
76
|
const collationKey = await this.verifyReentry();
|
|
@@ -98,7 +106,12 @@ class Activity {
|
|
|
98
106
|
this.logger.info('process-event-get-job-error', { ...error });
|
|
99
107
|
return;
|
|
100
108
|
}
|
|
101
|
-
this.logger.error('activity-process-event-error', {
|
|
109
|
+
this.logger.error('activity-process-event-error', {
|
|
110
|
+
...error,
|
|
111
|
+
message: error.message,
|
|
112
|
+
stack: error.stack,
|
|
113
|
+
name: error.name,
|
|
114
|
+
});
|
|
102
115
|
telemetry && telemetry.setActivityError(error.message);
|
|
103
116
|
throw error;
|
|
104
117
|
}
|
|
@@ -115,7 +128,7 @@ class Activity {
|
|
|
115
128
|
await this.setState(multi);
|
|
116
129
|
await collator_1.CollatorService.notarizeContinuation(this, multi);
|
|
117
130
|
await this.setStatus(this.adjacencyList.length, multi);
|
|
118
|
-
return await multi.exec();
|
|
131
|
+
return (await multi.exec());
|
|
119
132
|
}
|
|
120
133
|
async processSuccess(telemetry, type) {
|
|
121
134
|
this.bindActivityData(type);
|
|
@@ -125,7 +138,7 @@ class Activity {
|
|
|
125
138
|
await this.setState(multi);
|
|
126
139
|
await collator_1.CollatorService.notarizeCompletion(this, multi);
|
|
127
140
|
await this.setStatus(this.adjacencyList.length - 1, multi);
|
|
128
|
-
return await multi.exec();
|
|
141
|
+
return (await multi.exec());
|
|
129
142
|
}
|
|
130
143
|
async processError(telemetry, type) {
|
|
131
144
|
this.bindActivityError(this.data);
|
|
@@ -138,7 +151,7 @@ class Activity {
|
|
|
138
151
|
await this.setState(multi);
|
|
139
152
|
await collator_1.CollatorService.notarizeCompletion(this, multi);
|
|
140
153
|
await this.setStatus(this.adjacencyList.length - 1, multi);
|
|
141
|
-
return await multi.exec();
|
|
154
|
+
return (await multi.exec());
|
|
142
155
|
}
|
|
143
156
|
async transitionAdjacent(multiResponse, telemetry) {
|
|
144
157
|
telemetry.mapActivityAttributes();
|
|
@@ -223,7 +236,10 @@ class Activity {
|
|
|
223
236
|
* status and have no adjacent children to transition to) are bound to the job
|
|
224
237
|
*/
|
|
225
238
|
bindJobError(data) {
|
|
226
|
-
this.context.metadata.err = JSON.stringify({
|
|
239
|
+
this.context.metadata.err = JSON.stringify({
|
|
240
|
+
...data,
|
|
241
|
+
is_stream_error: true,
|
|
242
|
+
});
|
|
227
243
|
}
|
|
228
244
|
async getTriggerConfig() {
|
|
229
245
|
return await this.store.getSchema(this.config.trigger, await this.engine.getVID());
|
|
@@ -237,11 +253,11 @@ class Activity {
|
|
|
237
253
|
}
|
|
238
254
|
authorizeEntry(state) {
|
|
239
255
|
//pre-authorize activity state to allow entry for adjacent activities
|
|
240
|
-
return this.adjacencyList?.map((streamData) => {
|
|
241
|
-
const { metadata: { aid } } = streamData;
|
|
256
|
+
return (this.adjacencyList?.map((streamData) => {
|
|
257
|
+
const { metadata: { aid }, } = streamData;
|
|
242
258
|
state[`${aid}/output/metadata/as`] = collator_1.CollatorService.getSeed();
|
|
243
259
|
return aid;
|
|
244
|
-
}) ?? [];
|
|
260
|
+
}) ?? []);
|
|
245
261
|
}
|
|
246
262
|
bindDimensionalAddress(state) {
|
|
247
263
|
const dad = this.resolveDad();
|
|
@@ -251,7 +267,7 @@ class Activity {
|
|
|
251
267
|
const jobId = this.context.metadata.jid;
|
|
252
268
|
this.bindJobMetadata();
|
|
253
269
|
this.bindActivityMetadata();
|
|
254
|
-
|
|
270
|
+
const state = {};
|
|
255
271
|
await this.bindJobState(state);
|
|
256
272
|
const presets = this.authorizeEntry(state);
|
|
257
273
|
this.bindDimensionalAddress(state);
|
|
@@ -260,7 +276,7 @@ class Activity {
|
|
|
260
276
|
const symbolNames = [
|
|
261
277
|
`$${this.config.subscribes}`,
|
|
262
278
|
this.metadata.aid,
|
|
263
|
-
...presets
|
|
279
|
+
...presets,
|
|
264
280
|
];
|
|
265
281
|
const dIds = collator_1.CollatorService.getDimensionsById([...this.config.ancestors, this.metadata.aid], this.resolveDad());
|
|
266
282
|
return await this.store.setState(state, this.getJobStatus(), jobId, symbolNames, dIds, multi);
|
|
@@ -290,7 +306,7 @@ class Activity {
|
|
|
290
306
|
const triggerConfig = await this.getTriggerConfig();
|
|
291
307
|
const PRODUCES = [
|
|
292
308
|
...(triggerConfig.PRODUCES || []),
|
|
293
|
-
...this.bindJobMetadataPaths()
|
|
309
|
+
...this.bindJobMetadataPaths(),
|
|
294
310
|
];
|
|
295
311
|
for (const path of PRODUCES) {
|
|
296
312
|
const value = (0, utils_1.getValueByPath)(this.context, path);
|
|
@@ -298,7 +314,7 @@ class Activity {
|
|
|
298
314
|
state[path] = value;
|
|
299
315
|
}
|
|
300
316
|
}
|
|
301
|
-
for (
|
|
317
|
+
for (const key in this.context?.data ?? {}) {
|
|
302
318
|
if (key.startsWith('-') || key.startsWith('_')) {
|
|
303
319
|
state[key] = this.context.data[key];
|
|
304
320
|
}
|
|
@@ -308,7 +324,7 @@ class Activity {
|
|
|
308
324
|
bindActivityState(state) {
|
|
309
325
|
const produces = [
|
|
310
326
|
...this.config.produces,
|
|
311
|
-
...this.bindActivityMetadataPaths()
|
|
327
|
+
...this.bindActivityMetadataPaths(),
|
|
312
328
|
];
|
|
313
329
|
for (const path of produces) {
|
|
314
330
|
const prefixedPath = `${this.metadata.aid}/${path}`;
|
|
@@ -330,7 +346,7 @@ class Activity {
|
|
|
330
346
|
const gid = this.context.metadata.gid;
|
|
331
347
|
const jobSymbolHashName = `$${this.config.subscribes}`;
|
|
332
348
|
const consumes = {
|
|
333
|
-
[jobSymbolHashName]: serializer_1.MDATA_SYMBOLS.JOB.KEYS.map((key) => `metadata/${key}`)
|
|
349
|
+
[jobSymbolHashName]: serializer_1.MDATA_SYMBOLS.JOB.KEYS.map((key) => `metadata/${key}`),
|
|
334
350
|
};
|
|
335
351
|
for (let [activityId, paths] of Object.entries(this.config.consumes)) {
|
|
336
352
|
if (activityId === '$job') {
|
|
@@ -351,7 +367,7 @@ class Activity {
|
|
|
351
367
|
}
|
|
352
368
|
}
|
|
353
369
|
telemetry_1.TelemetryService.addTargetTelemetryPaths(consumes, this.config, this.metadata, this.leg);
|
|
354
|
-
|
|
370
|
+
const { dad, jid } = this.context.metadata;
|
|
355
371
|
const dIds = collator_1.CollatorService.getDimensionsById([...this.config.ancestors, this.metadata.aid], dad || '');
|
|
356
372
|
//`state` is a unidimensional hash; context is a tree
|
|
357
373
|
const [state, _status] = await this.store.getState(jid, consumes, dIds);
|
|
@@ -418,7 +434,6 @@ class Activity {
|
|
|
418
434
|
//concat self and child dimension (all children (leg 1) begin life at 0)
|
|
419
435
|
return `${this.resolveDad()}${collator_1.CollatorService.getDimensionalSeed(0)}`;
|
|
420
436
|
}
|
|
421
|
-
;
|
|
422
437
|
async filterAdjacent() {
|
|
423
438
|
const adjacencyList = [];
|
|
424
439
|
const transitions = await this.store.getTransitions(await this.engine.getVID());
|
|
@@ -440,7 +455,7 @@ class Activity {
|
|
|
440
455
|
trc: this.context.metadata.trc,
|
|
441
456
|
},
|
|
442
457
|
type: stream_1.StreamDataType.TRANSITION,
|
|
443
|
-
data: {}
|
|
458
|
+
data: {},
|
|
444
459
|
});
|
|
445
460
|
}
|
|
446
461
|
}
|
|
@@ -457,7 +472,9 @@ class Activity {
|
|
|
457
472
|
emit = pipe_1.Pipe.resolve(this.config.emit, this.context);
|
|
458
473
|
}
|
|
459
474
|
if (jobStatus <= 0 || emit) {
|
|
460
|
-
await this.engine.runJobCompletionTasks(this.context, {
|
|
475
|
+
await this.engine.runJobCompletionTasks(this.context, {
|
|
476
|
+
emit: jobStatus > 0,
|
|
477
|
+
});
|
|
461
478
|
}
|
|
462
479
|
if (adjacencyList.length && jobStatus > 0) {
|
|
463
480
|
const multi = this.store.getMulti();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Activity } from './activity';
|
|
2
1
|
import { EngineService } from '../engine';
|
|
3
2
|
import { ActivityData, ActivityMetadata, AwaitActivity, ActivityType } from '../../types/activity';
|
|
4
3
|
import { JobState } from '../../types/job';
|
|
5
4
|
import { RedisMulti } from '../../types/redis';
|
|
5
|
+
import { Activity } from './activity';
|
|
6
6
|
declare class Await extends Activity {
|
|
7
7
|
config: AwaitActivity;
|
|
8
8
|
constructor(config: ActivityType, data: ActivityData, metadata: ActivityMetadata, hook: ActivityData | null, engine: EngineService, context?: JobState);
|