@hotmeshio/hotmesh 0.0.55 → 0.0.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/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 +57 -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 +25 -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 +121 -3
- 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
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
class StringHandler {
|
|
2
|
-
split(input: string, delimiter: string): string[] {
|
|
3
|
-
return input.split(delimiter);
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
charAt(input: string, index: number): string {
|
|
7
|
-
return input.charAt(index);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
concat(...strings: string[]): string {
|
|
11
|
-
return strings.join('');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
includes(input: string, searchString: string, position?: number): boolean {
|
|
15
|
-
return input.includes(searchString, position);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
indexOf(input: string, searchString: string, fromIndex?: number): number {
|
|
19
|
-
return input.indexOf(searchString, fromIndex);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
lastIndexOf(input: string, searchString: string, fromIndex?: number): number {
|
|
23
|
-
return input.lastIndexOf(searchString, fromIndex);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
slice(input: string, start?: number, end?: number): string {
|
|
27
|
-
return input.slice(start, end);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
toLowerCase(input: string): string {
|
|
31
|
-
return input.toLowerCase();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
toUpperCase(input: string): string {
|
|
35
|
-
return input.toUpperCase();
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
trim(input: string): string {
|
|
39
|
-
return input.trim();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
trimStart(input: string): string {
|
|
43
|
-
return input.trimStart();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
trimEnd(input: string): string {
|
|
47
|
-
return input.trimEnd();
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
padStart(input: string, maxLength: number, padString?: string): string {
|
|
51
|
-
return input.padStart(maxLength, padString);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
padEnd(input: string, maxLength: number, padString?: string): string {
|
|
55
|
-
return input.padEnd(maxLength, padString);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
replace(input: string, searchValue: string | RegExp, replaceValue: string): string {
|
|
59
|
-
return input.replace(searchValue, replaceValue);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
search(input: string, regexp: RegExp): number {
|
|
63
|
-
return input.search(regexp);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
substring(input: string, start: number, end?: number): string {
|
|
67
|
-
return input.substring(start, end);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
startsWith(str: string, searchString: string, position?: number): boolean {
|
|
71
|
-
return str.startsWith(searchString, position);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
endsWith(str: string, searchString: string, length?: number): boolean {
|
|
75
|
-
return str.endsWith(searchString, length);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
repeat(str: string, count: number): string {
|
|
79
|
-
if (count < 0 || count === Infinity) {
|
|
80
|
-
throw new RangeError('Invalid repeat count. Must be a positive finite number.');
|
|
81
|
-
}
|
|
82
|
-
return str.repeat(count);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export { StringHandler };
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
class SymbolHandler {
|
|
2
|
-
null(): null {
|
|
3
|
-
return null;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
undefined(): undefined {
|
|
7
|
-
return undefined;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
whitespace(): string {
|
|
11
|
-
return ' ';
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
object(): object {
|
|
15
|
-
return {};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
array(): any[] {
|
|
19
|
-
return [];
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
posInfinity(): number {
|
|
23
|
-
return Infinity;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
negInfinity(): number {
|
|
27
|
-
return -Infinity;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
NaN(): number {
|
|
31
|
-
return NaN;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
date(): Date {
|
|
35
|
-
return new Date();
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export { SymbolHandler };
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
class UnaryHandler {
|
|
2
|
-
not(value: boolean): boolean {
|
|
3
|
-
return !value;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
positive(value: number): number {
|
|
7
|
-
return +value;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
negative(value: number): number {
|
|
11
|
-
return -value;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
bitwise_not(value: number): number {
|
|
15
|
-
return ~value;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export { UnaryHandler };
|
package/services/pipe/index.ts
DELETED
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import FUNCTIONS from './functions'
|
|
2
|
-
import { JobState, JobData, JobsData } from '../../types/job';
|
|
3
|
-
import {
|
|
4
|
-
PipeContext,
|
|
5
|
-
PipeItem,
|
|
6
|
-
PipeItems,
|
|
7
|
-
PipeObject,
|
|
8
|
-
Pipe as PipeType,
|
|
9
|
-
ReduceObject } from '../../types/pipe';
|
|
10
|
-
|
|
11
|
-
class Pipe {
|
|
12
|
-
rules: PipeType;
|
|
13
|
-
jobData: JobData;
|
|
14
|
-
context: PipeContext;
|
|
15
|
-
|
|
16
|
-
constructor(rules: PipeType, jobData: JobData, context?: PipeContext) {
|
|
17
|
-
this.rules = rules;
|
|
18
|
-
this.jobData = jobData;
|
|
19
|
-
this.context = context;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
private isPipeType(currentRow: PipeItem[] | PipeType | PipeObject | ReduceObject): currentRow is PipeType {
|
|
23
|
-
return !Array.isArray(currentRow) && '@pipe' in currentRow;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
private isreduceType(currentRow: PipeItem[] | PipeType | PipeObject | ReduceObject): currentRow is PipeType {
|
|
27
|
-
return !Array.isArray(currentRow) && '@reduce' in currentRow;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
static isPipeObject(obj: { [key: string]: unknown } | PipeItem): boolean {
|
|
32
|
-
return typeof obj === 'object' && obj !== null && !Array.isArray(obj) && '@pipe' in obj;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
static resolve(unresolved: { [key: string]: unknown }|PipeItem, context: Partial<JobState>): any {
|
|
36
|
-
let pipe: Pipe;
|
|
37
|
-
if (Pipe.isPipeObject(unresolved)) {
|
|
38
|
-
pipe = new Pipe(unresolved['@pipe'], context);
|
|
39
|
-
} else {
|
|
40
|
-
pipe = new Pipe([[unresolved as unknown as PipeItem]], context);
|
|
41
|
-
}
|
|
42
|
-
return pipe.process();
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* loop through each PipeItem row in this Pipe, resolving and transforming line by line
|
|
47
|
-
* @returns {any} the result of the pipe
|
|
48
|
-
*/
|
|
49
|
-
process(resolved: unknown[] | null = null): any {
|
|
50
|
-
let index = 0;
|
|
51
|
-
if (!(resolved || this.isPipeType(this.rules[0]) || this.isreduceType(this.rules[0]))) {
|
|
52
|
-
resolved = this.processCells(this.rules[0] as PipeItem[]); // Add type assertion
|
|
53
|
-
index = 1;
|
|
54
|
-
}
|
|
55
|
-
const len = this.rules.length;
|
|
56
|
-
const subPipeQueue = [];
|
|
57
|
-
for (let i = index; i < len; i++) {
|
|
58
|
-
resolved = this.processRow(this.rules[i], resolved, subPipeQueue);
|
|
59
|
-
}
|
|
60
|
-
return resolved[0];
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Transforms iterable `input` into a single value. Vars $output, $item, $key
|
|
65
|
-
* and $input are available. The final statement in the iterator (the reduction)
|
|
66
|
-
* is assumed to be the return value. A default $output object may be provided
|
|
67
|
-
* to the iterator by placing the the second cell of the preceding row. Otherwise,
|
|
68
|
-
* construct the object during first run and ensure it is the first cell of the
|
|
69
|
-
* last row of the iterator, so it is returned as the $output for the next cycle
|
|
70
|
-
* @param {unknown[]} input
|
|
71
|
-
* @returns {unknown}
|
|
72
|
-
* @private
|
|
73
|
-
*/
|
|
74
|
-
reduce(input: Array<unknown[]>): unknown {
|
|
75
|
-
let resolved = input[1] ?? null;
|
|
76
|
-
|
|
77
|
-
if (Array.isArray(input[0])) {
|
|
78
|
-
for (let index = 0; index < input[0].length; index++) {
|
|
79
|
-
this.context = { $input: input[0], $output: resolved, $item: input[0][index], $key: index.toString(), $index: index };
|
|
80
|
-
resolved = this.process([resolved]);
|
|
81
|
-
}
|
|
82
|
-
} else {
|
|
83
|
-
let index = -1;
|
|
84
|
-
for (let $key in (input[0] as Record<string, unknown>)) {
|
|
85
|
-
index++;
|
|
86
|
-
this.context = { $input: input[0], $output: resolved, $item: input[0][$key], $key, $index: index };
|
|
87
|
-
resolved = this.process([resolved]);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return [resolved];
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
private processRow(currentRow: PipeItem[] | PipeType | PipeObject | ReduceObject , resolvedPriorRow: unknown[]|null, subPipeQueue: unknown[]): PipeItem[] {
|
|
94
|
-
if (resolvedPriorRow && this.isreduceType(currentRow)) {
|
|
95
|
-
//reduce the resolvedPriorRow and return the output from the reducer
|
|
96
|
-
const subPipe = new Pipe(currentRow['@reduce'], this.jobData);
|
|
97
|
-
const reduced = subPipe.reduce(resolvedPriorRow as Array<unknown[]>)
|
|
98
|
-
return reduced as PipeItem[];
|
|
99
|
-
} else if (this.isPipeType(currentRow)) {
|
|
100
|
-
//process subPipe and push to subPipeQueue; echo resolvedPriorRow
|
|
101
|
-
const subPipe = new Pipe(currentRow['@pipe'], this.jobData, this.context);
|
|
102
|
-
subPipeQueue.push(subPipe.process());
|
|
103
|
-
return resolvedPriorRow as PipeItem[];
|
|
104
|
-
} else {
|
|
105
|
-
//pivot the subPipeQueue into the arguments array (resolvedPriorRow)
|
|
106
|
-
if (subPipeQueue.length > 0) {
|
|
107
|
-
resolvedPriorRow = [...subPipeQueue];
|
|
108
|
-
subPipeQueue.length = 0;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (!resolvedPriorRow) {
|
|
112
|
-
//if no prior row, use current row as prior row
|
|
113
|
-
return [].concat(this.processCells(Array.isArray(currentRow) ? [...currentRow] as PipeItem[] : []));
|
|
114
|
-
} else {
|
|
115
|
-
const [functionName, ...params] = currentRow as PipeItem[]; // Add type assertion
|
|
116
|
-
//use resolved values from prior row (n - 1) as input params to cell 1 function
|
|
117
|
-
let resolvedValue: unknown;
|
|
118
|
-
if (this.isContextVariable(functionName)) {
|
|
119
|
-
resolvedValue = this.resolveContextValue(functionName as string);
|
|
120
|
-
} else {
|
|
121
|
-
resolvedValue = Pipe.resolveFunction(functionName as string)(...resolvedPriorRow);
|
|
122
|
-
}
|
|
123
|
-
//resolve remaining cells in row and return concatenated with resolvedValue
|
|
124
|
-
return [(resolvedValue as PipeItem)].concat(this.processCells([...params]));
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
static resolveFunction(functionName: string) {
|
|
130
|
-
let [prefix, suffix] = functionName.split('.');
|
|
131
|
-
prefix = prefix.substring(2);
|
|
132
|
-
suffix = suffix.substring(0, suffix.length - 1);
|
|
133
|
-
const domain = FUNCTIONS[prefix];
|
|
134
|
-
if (!domain) {
|
|
135
|
-
throw new Error(`Unknown domain name [${functionName}]: ${prefix}`);
|
|
136
|
-
}
|
|
137
|
-
if (!domain[suffix]) {
|
|
138
|
-
throw new Error(`Unknown domain function [${functionName}]: ${prefix}.${suffix}`);
|
|
139
|
-
}
|
|
140
|
-
return domain[suffix];
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
processCells(cells: PipeItems): unknown[] {
|
|
144
|
-
const resolved = [];
|
|
145
|
-
if (Array.isArray(cells)) {
|
|
146
|
-
for (const currentCell of cells) {
|
|
147
|
-
resolved.push(this.resolveCellValue(currentCell));
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return resolved;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
private isFunction(currentCell: PipeItem): boolean {
|
|
154
|
-
return typeof currentCell === 'string' && currentCell.startsWith('{@') && currentCell.endsWith('}');
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
private isContextVariable(currentCell: PipeItem): boolean {
|
|
158
|
-
if(typeof currentCell === 'string' && currentCell.endsWith('}')) {
|
|
159
|
-
return currentCell.startsWith('{$item') || currentCell.startsWith('{$key') || currentCell.startsWith('{$index') || currentCell.startsWith('{$input') || currentCell.startsWith('{$output');
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
private isMappable(currentCell: PipeItem): boolean {
|
|
164
|
-
return typeof currentCell === 'string' && currentCell.startsWith('{') && currentCell.endsWith('}');
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
resolveCellValue(currentCell: PipeItem): unknown {
|
|
168
|
-
if (this.isFunction(currentCell)) {
|
|
169
|
-
const fn = Pipe.resolveFunction(currentCell as string);
|
|
170
|
-
return fn.call();
|
|
171
|
-
} else if (this.isContextVariable(currentCell)) {
|
|
172
|
-
return this.resolveContextValue(currentCell as string);
|
|
173
|
-
} else if (this.isMappable(currentCell)) {
|
|
174
|
-
return this.resolveMappableValue(currentCell as string);
|
|
175
|
-
} else {
|
|
176
|
-
return currentCell;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
private getNestedProperty(obj: JobsData|unknown, path: string): any {
|
|
181
|
-
const pathParts = path.split('.');
|
|
182
|
-
let current = obj;
|
|
183
|
-
for (const part of pathParts) {
|
|
184
|
-
if (current === null || typeof current !== 'object' || !current.hasOwnProperty(part)) {
|
|
185
|
-
return undefined;
|
|
186
|
-
}
|
|
187
|
-
current = current[part];
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return current;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
resolveMappableValue(currentCell: string): unknown {
|
|
194
|
-
const term = this.resolveMapTerm(currentCell);
|
|
195
|
-
return this.getNestedProperty(this.jobData, term);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
resolveContextValue(currentCell: string): unknown {
|
|
199
|
-
const term = this.resolveContextTerm(currentCell);
|
|
200
|
-
return this.getNestedProperty(this.context, term);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
resolveContextTerm(currentCell: string): string {
|
|
204
|
-
return currentCell.substring(1, currentCell.length - 1);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
resolveFunctionTerm(currentCell: string): string {
|
|
208
|
-
return currentCell.substring(2, currentCell.length - 1);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
resolveMapTerm(currentCell: string): string {
|
|
212
|
-
return currentCell.substring(1, currentCell.length - 1);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export { Pipe };
|
package/services/quorum/index.ts
DELETED
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
HMSH_ACTIVATION_MAX_RETRY,
|
|
3
|
-
HMSH_QUORUM_DELAY_MS,
|
|
4
|
-
HMSH_QUORUM_ROLLCALL_CYCLES} from '../../modules/enums';
|
|
5
|
-
import {
|
|
6
|
-
XSleepFor,
|
|
7
|
-
formatISODate,
|
|
8
|
-
getSystemHealth,
|
|
9
|
-
identifyRedisType,
|
|
10
|
-
sleepFor } from '../../modules/utils';
|
|
11
|
-
import { CompilerService } from '../compiler';
|
|
12
|
-
import { EngineService } from '../engine';
|
|
13
|
-
import { ILogger } from '../logger';
|
|
14
|
-
import { StoreService } from '../store';
|
|
15
|
-
import { IORedisStoreService as IORedisStore } from '../store/clients/ioredis';
|
|
16
|
-
import { RedisStoreService as RedisStore } from '../store/clients/redis';
|
|
17
|
-
import { SubService } from '../sub';
|
|
18
|
-
import { IORedisSubService as IORedisSub } from '../sub/clients/ioredis';
|
|
19
|
-
import { RedisSubService as RedisSub } from '../sub/clients/redis';
|
|
20
|
-
import { CacheMode } from '../../types/cache';
|
|
21
|
-
import { HotMeshConfig, KeyType } from '../../types/hotmesh';
|
|
22
|
-
import { RedisClientType as IORedisClientType } from '../../types/ioredisclient';
|
|
23
|
-
import {
|
|
24
|
-
QuorumMessage,
|
|
25
|
-
QuorumMessageCallback,
|
|
26
|
-
QuorumProfile,
|
|
27
|
-
RollCallMessage,
|
|
28
|
-
SubscriptionCallback } from '../../types/quorum';
|
|
29
|
-
import { RedisClient, RedisMulti } from '../../types/redis';
|
|
30
|
-
import { RedisClientType } from '../../types/redisclient';
|
|
31
|
-
|
|
32
|
-
class QuorumService {
|
|
33
|
-
namespace: string;
|
|
34
|
-
appId: string;
|
|
35
|
-
guid: string;
|
|
36
|
-
engine: EngineService;
|
|
37
|
-
profiles: QuorumProfile[] = [];
|
|
38
|
-
store: StoreService<RedisClient, RedisMulti> | null;
|
|
39
|
-
subscribe: SubService<RedisClient, RedisMulti> | null;
|
|
40
|
-
logger: ILogger;
|
|
41
|
-
cacheMode: CacheMode = 'cache';
|
|
42
|
-
untilVersion: string | null = null;
|
|
43
|
-
quorum: number | null = null;
|
|
44
|
-
callbacks: QuorumMessageCallback[] = [];
|
|
45
|
-
rollCallInterval: NodeJS.Timeout;
|
|
46
|
-
|
|
47
|
-
static async init(
|
|
48
|
-
namespace: string,
|
|
49
|
-
appId: string,
|
|
50
|
-
guid: string,
|
|
51
|
-
config: HotMeshConfig,
|
|
52
|
-
engine: EngineService,
|
|
53
|
-
logger: ILogger
|
|
54
|
-
): Promise<QuorumService> {
|
|
55
|
-
if (config.engine) {
|
|
56
|
-
const instance = new QuorumService();
|
|
57
|
-
instance.verifyQuorumFields(config);
|
|
58
|
-
instance.namespace = namespace;
|
|
59
|
-
instance.appId = appId;
|
|
60
|
-
instance.guid = guid;
|
|
61
|
-
instance.logger = logger;
|
|
62
|
-
instance.engine = engine;
|
|
63
|
-
|
|
64
|
-
//note: `quorum` shares/re-uses the engine's `store`/`sub` Redis clients
|
|
65
|
-
await instance.initStoreChannel(config.engine.store);
|
|
66
|
-
await instance.initSubChannel(config.engine.sub);
|
|
67
|
-
//general quorum subscription
|
|
68
|
-
await instance.subscribe.subscribe(
|
|
69
|
-
KeyType.QUORUM,
|
|
70
|
-
instance.subscriptionHandler(),
|
|
71
|
-
appId
|
|
72
|
-
);
|
|
73
|
-
//app-specific quorum subscription (used for pubsub one-time request/response)
|
|
74
|
-
await instance.subscribe.subscribe(
|
|
75
|
-
KeyType.QUORUM,
|
|
76
|
-
instance.subscriptionHandler(),
|
|
77
|
-
appId, instance.guid
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
instance.engine.processWebHooks();
|
|
81
|
-
instance.engine.processTimeHooks();
|
|
82
|
-
return instance;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
verifyQuorumFields(config: HotMeshConfig) {
|
|
87
|
-
if (!identifyRedisType(config.engine.store) ||
|
|
88
|
-
!identifyRedisType(config.engine.sub)) {
|
|
89
|
-
throw new Error('quorum config must include `store` and `sub` fields.');
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async initStoreChannel(store: RedisClient) {
|
|
94
|
-
if (identifyRedisType(store) === 'redis') {
|
|
95
|
-
this.store = new RedisStore(store as RedisClientType);
|
|
96
|
-
} else {
|
|
97
|
-
this.store = new IORedisStore(store as IORedisClientType);
|
|
98
|
-
}
|
|
99
|
-
await this.store.init(
|
|
100
|
-
this.namespace,
|
|
101
|
-
this.appId,
|
|
102
|
-
this.logger
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
async initSubChannel(sub: RedisClient) {
|
|
107
|
-
if (identifyRedisType(sub) === 'redis') {
|
|
108
|
-
this.subscribe = new RedisSub(sub as RedisClientType);
|
|
109
|
-
} else {
|
|
110
|
-
this.subscribe = new IORedisSub(sub as IORedisClientType);
|
|
111
|
-
}
|
|
112
|
-
await this.subscribe.init(
|
|
113
|
-
this.namespace,
|
|
114
|
-
this.appId,
|
|
115
|
-
this.guid,
|
|
116
|
-
this.logger
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
subscriptionHandler(): SubscriptionCallback {
|
|
121
|
-
const self = this;
|
|
122
|
-
return async (topic: string, message: QuorumMessage) => {
|
|
123
|
-
self.logger.debug('quorum-event-received', { topic, type: message.type});
|
|
124
|
-
if (message.type === 'activate') {
|
|
125
|
-
self.engine.setCacheMode(message.cache_mode, message.until_version);
|
|
126
|
-
} else if (message.type === 'ping') {
|
|
127
|
-
self.sayPong(self.appId, self.guid, message.originator, message.details);
|
|
128
|
-
} else if (message.type === 'pong' && self.guid === message.originator) {
|
|
129
|
-
self.quorum = self.quorum + 1;
|
|
130
|
-
if (message.profile) {
|
|
131
|
-
self.profiles.push(message.profile);
|
|
132
|
-
}
|
|
133
|
-
} else if (message.type === 'throttle') {
|
|
134
|
-
self.engine.throttle(message.throttle);
|
|
135
|
-
} else if (message.type === 'work') {
|
|
136
|
-
self.engine.processWebHooks()
|
|
137
|
-
} else if (message.type === 'job') {
|
|
138
|
-
self.engine.routeToSubscribers(message.topic, message.job)
|
|
139
|
-
} else if (message.type === 'cron') {
|
|
140
|
-
self.engine.processTimeHooks();
|
|
141
|
-
} else if (message.type === 'rollcall') {
|
|
142
|
-
self.doRollCall(message);
|
|
143
|
-
}
|
|
144
|
-
//if there are any callbacks, call them
|
|
145
|
-
if (self.callbacks.length > 0) {
|
|
146
|
-
self.callbacks.forEach(cb => cb(topic, message));
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async sayPong(appId: string, guid: string, originator: string, details = false) {
|
|
152
|
-
let profile: QuorumProfile;
|
|
153
|
-
if (details) {
|
|
154
|
-
const stream = this.engine.stream.mintKey(
|
|
155
|
-
KeyType.STREAMS,
|
|
156
|
-
{ appId: this.appId }
|
|
157
|
-
);
|
|
158
|
-
profile = {
|
|
159
|
-
engine_id: this.guid,
|
|
160
|
-
namespace: this.namespace,
|
|
161
|
-
app_id: this.appId,
|
|
162
|
-
stream,
|
|
163
|
-
counts: this.engine.router.counts,
|
|
164
|
-
timestamp: formatISODate(new Date()),
|
|
165
|
-
inited: this.engine.inited,
|
|
166
|
-
throttle: this.engine.router.throttle,
|
|
167
|
-
reclaimDelay: this.engine.router.reclaimDelay,
|
|
168
|
-
reclaimCount: this.engine.router.reclaimCount,
|
|
169
|
-
system: await getSystemHealth(),
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
this.store.publish(
|
|
173
|
-
KeyType.QUORUM,
|
|
174
|
-
{
|
|
175
|
-
type: 'pong',
|
|
176
|
-
guid, originator,
|
|
177
|
-
profile,
|
|
178
|
-
},
|
|
179
|
-
appId,
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
async requestQuorum(delay = HMSH_QUORUM_DELAY_MS, details = false): Promise<number> {
|
|
184
|
-
const quorum = this.quorum;
|
|
185
|
-
this.quorum = 0;
|
|
186
|
-
this.profiles.length = 0;
|
|
187
|
-
await this.store.publish(
|
|
188
|
-
KeyType.QUORUM,
|
|
189
|
-
{
|
|
190
|
-
type: 'ping',
|
|
191
|
-
originator: this.guid,
|
|
192
|
-
details,
|
|
193
|
-
},
|
|
194
|
-
this.appId,
|
|
195
|
-
);
|
|
196
|
-
await sleepFor(delay);
|
|
197
|
-
return quorum;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* A quorum-wide command to broadcaset system details.
|
|
202
|
-
*
|
|
203
|
-
*/
|
|
204
|
-
async doRollCall(message: RollCallMessage) {
|
|
205
|
-
let iteration = 0;
|
|
206
|
-
let max = !isNaN(message.max) ? message.max : HMSH_QUORUM_ROLLCALL_CYCLES;
|
|
207
|
-
if (this.rollCallInterval) clearTimeout(this.rollCallInterval);
|
|
208
|
-
const base = (message.interval / 2);
|
|
209
|
-
const amount = base + Math.ceil(Math.random() * base);
|
|
210
|
-
do {
|
|
211
|
-
await sleepFor(Math.ceil(Math.random() * 1000));
|
|
212
|
-
await this.sayPong(this.appId, this.guid, null, true);
|
|
213
|
-
if (!message.interval) return;
|
|
214
|
-
const { promise, timerId } = XSleepFor(amount * 1000);
|
|
215
|
-
this.rollCallInterval = timerId;
|
|
216
|
-
await promise;
|
|
217
|
-
} while (this.rollCallInterval && iteration++ < max - 1);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
cancelRollCall() {
|
|
221
|
-
if (this.rollCallInterval) {
|
|
222
|
-
clearTimeout(this.rollCallInterval);
|
|
223
|
-
delete this.rollCallInterval;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
stop() {
|
|
228
|
-
this.cancelRollCall();
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// ************* PUB/SUB METHODS *************
|
|
232
|
-
//publish a message to the quorum
|
|
233
|
-
async pub(quorumMessage: QuorumMessage) {
|
|
234
|
-
return await this.store.publish(KeyType.QUORUM, quorumMessage, this.appId, quorumMessage.topic || quorumMessage.guid);
|
|
235
|
-
}
|
|
236
|
-
//subscribe user to quorum messages
|
|
237
|
-
async sub(callback: QuorumMessageCallback): Promise<void> {
|
|
238
|
-
//the quorum is always subscribed to the `quorum` topic; just register the fn
|
|
239
|
-
this.callbacks.push(callback);
|
|
240
|
-
}
|
|
241
|
-
//unsubscribe user from quorum messages
|
|
242
|
-
async unsub(callback: QuorumMessageCallback): Promise<void> {
|
|
243
|
-
//the quorum is always subscribed to the `quorum` topic; just unregister the fn
|
|
244
|
-
this.callbacks = this.callbacks.filter(cb => cb !== callback);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
// ************* COMPILER METHODS *************
|
|
249
|
-
async rollCall(delay = HMSH_QUORUM_DELAY_MS): Promise<QuorumProfile[]> {
|
|
250
|
-
await this.requestQuorum(delay, true);
|
|
251
|
-
const targetStreams = [];
|
|
252
|
-
const multi = this.store.getMulti();
|
|
253
|
-
this.profiles.forEach((profile: QuorumProfile) => {
|
|
254
|
-
if (!targetStreams.includes(profile.stream)) {
|
|
255
|
-
targetStreams.push(profile.stream);
|
|
256
|
-
this.store.xlen(profile.stream, multi);
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
const stream_depths = await multi.exec() as number[];
|
|
260
|
-
this.profiles.forEach(async (profile: QuorumProfile) => {
|
|
261
|
-
const index = targetStreams.indexOf(profile.stream);
|
|
262
|
-
if (index != -1) {
|
|
263
|
-
profile.stream_depth = Array.isArray(stream_depths[index]) ?
|
|
264
|
-
stream_depths[index][1] :
|
|
265
|
-
stream_depths[index];
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
return this.profiles;
|
|
269
|
-
}
|
|
270
|
-
/**
|
|
271
|
-
* request a quorum; if successful activate the app version
|
|
272
|
-
*/
|
|
273
|
-
async activate(version: string, delay = HMSH_QUORUM_DELAY_MS, count = 0): Promise<boolean> {
|
|
274
|
-
version = version.toString();
|
|
275
|
-
const canActivate = await this.store.reserveScoutRole('activate', Math.ceil(delay * 6 / 1000) + 1);
|
|
276
|
-
if (!canActivate) {
|
|
277
|
-
//another engine is already activating the app version
|
|
278
|
-
this.logger.debug('quorum-activation-awaiting', { version });
|
|
279
|
-
await sleepFor(delay * 6);
|
|
280
|
-
const app = await this.store.getApp(this.appId, true);
|
|
281
|
-
return app?.active == true && app?.version === version;
|
|
282
|
-
}
|
|
283
|
-
const config = await this.engine.getVID();
|
|
284
|
-
await this.requestQuorum(delay);
|
|
285
|
-
const q1 = await this.requestQuorum(delay);
|
|
286
|
-
const q2 = await this.requestQuorum(delay);
|
|
287
|
-
const q3 = await this.requestQuorum(delay);
|
|
288
|
-
if (q1 && q1 === q2 && q2 === q3) {
|
|
289
|
-
this.logger.info('quorum-rollcall-succeeded', { q1, q2, q3 });
|
|
290
|
-
this.store.publish(
|
|
291
|
-
KeyType.QUORUM,
|
|
292
|
-
{ type: 'activate', cache_mode: 'nocache', until_version: version },
|
|
293
|
-
this.appId
|
|
294
|
-
);
|
|
295
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
296
|
-
await this.store.releaseScoutRole('activate');
|
|
297
|
-
//confirm we received the activation message
|
|
298
|
-
if (this.engine.untilVersion === version) {
|
|
299
|
-
this.logger.info('quorum-activation-succeeded', { version });
|
|
300
|
-
const { id } = config;
|
|
301
|
-
const compiler = new CompilerService(this.store, this.logger);
|
|
302
|
-
return await compiler.activate(id, version);
|
|
303
|
-
} else {
|
|
304
|
-
this.logger.error('quorum-activation-error', { version });
|
|
305
|
-
throw new Error(`UntilVersion Not Received. Version ${version} not activated`);
|
|
306
|
-
}
|
|
307
|
-
} else {
|
|
308
|
-
this.logger.warn('quorum-rollcall-error', { q1, q2, q3, count });
|
|
309
|
-
this.store.releaseScoutRole('activate');
|
|
310
|
-
if (count < HMSH_ACTIVATION_MAX_RETRY) {
|
|
311
|
-
//increase the delay (give the quorum time to respond) and try again
|
|
312
|
-
return await this.activate(version, delay * 2, count + 1);
|
|
313
|
-
}
|
|
314
|
-
throw new Error(`Quorum not reached. Version ${version} not activated.`);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
export { QuorumService }
|