@hotmeshio/hotmesh 0.3.4 → 0.3.6
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/index.d.ts +5 -4
- package/build/index.js +7 -5
- package/build/modules/utils.d.ts +1 -0
- package/build/modules/utils.js +26 -1
- package/build/package.json +3 -2
- package/build/services/activities/trigger.d.ts +0 -1
- package/build/services/activities/trigger.js +0 -32
- package/build/services/engine/index.js +6 -27
- package/build/services/meshflow/client.js +2 -2
- package/build/services/meshflow/search.js +3 -1
- package/build/services/meshflow/worker.js +1 -1
- package/build/services/meshflow/workflow.js +6 -4
- package/build/services/meshos/index.d.ts +81 -0
- package/build/services/meshos/index.js +339 -0
- package/build/services/quorum/index.js +4 -18
- package/build/services/store/factory.d.ts +7 -0
- package/build/services/store/factory.js +20 -0
- package/build/services/store/index.d.ts +0 -1
- package/build/services/store/index.js +0 -2
- package/build/services/stream/factory.d.ts +7 -0
- package/build/services/stream/factory.js +20 -0
- package/build/services/sub/factory.d.ts +7 -0
- package/build/services/sub/factory.js +20 -0
- package/build/services/worker/index.js +6 -27
- package/build/types/index.d.ts +1 -0
- package/build/types/manifest.d.ts +49 -0
- package/build/types/manifest.js +2 -0
- package/index.ts +5 -4
- package/package.json +3 -2
- package/typedoc.json +1 -0
- package/types/index.ts +15 -0
- package/types/manifest.ts +68 -0
- package/types/meshflow.ts +1 -1
package/build/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { MeshCall } from './services/meshcall';
|
|
2
|
-
import { MeshData } from './services/meshdata';
|
|
3
|
-
import { MeshFlow } from './services/meshflow';
|
|
4
1
|
import { HotMesh } from './services/hotmesh';
|
|
5
2
|
import { HotMeshConfig } from './types/hotmesh';
|
|
6
|
-
|
|
3
|
+
import { MeshCall } from './services/meshcall';
|
|
4
|
+
import { MeshFlow } from './services/meshflow';
|
|
5
|
+
import { MeshData } from './services/meshdata';
|
|
6
|
+
import { MeshOS } from './services/meshos';
|
|
7
|
+
export { HotMesh, HotMeshConfig, MeshCall, MeshData, MeshFlow, MeshOS };
|
|
7
8
|
export * as Types from './types';
|
package/build/index.js
CHANGED
|
@@ -23,13 +23,15 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.Types = exports.MeshFlow = exports.MeshData = exports.MeshCall = exports.HotMesh = void 0;
|
|
26
|
+
exports.Types = exports.MeshOS = exports.MeshFlow = exports.MeshData = exports.MeshCall = exports.HotMesh = void 0;
|
|
27
|
+
const hotmesh_1 = require("./services/hotmesh");
|
|
28
|
+
Object.defineProperty(exports, "HotMesh", { enumerable: true, get: function () { return hotmesh_1.HotMesh; } });
|
|
27
29
|
const meshcall_1 = require("./services/meshcall");
|
|
28
30
|
Object.defineProperty(exports, "MeshCall", { enumerable: true, get: function () { return meshcall_1.MeshCall; } });
|
|
29
|
-
const meshdata_1 = require("./services/meshdata");
|
|
30
|
-
Object.defineProperty(exports, "MeshData", { enumerable: true, get: function () { return meshdata_1.MeshData; } });
|
|
31
31
|
const meshflow_1 = require("./services/meshflow");
|
|
32
32
|
Object.defineProperty(exports, "MeshFlow", { enumerable: true, get: function () { return meshflow_1.MeshFlow; } });
|
|
33
|
-
const
|
|
34
|
-
Object.defineProperty(exports, "
|
|
33
|
+
const meshdata_1 = require("./services/meshdata");
|
|
34
|
+
Object.defineProperty(exports, "MeshData", { enumerable: true, get: function () { return meshdata_1.MeshData; } });
|
|
35
|
+
const meshos_1 = require("./services/meshos");
|
|
36
|
+
Object.defineProperty(exports, "MeshOS", { enumerable: true, get: function () { return meshos_1.MeshOS; } });
|
|
35
37
|
exports.Types = __importStar(require("./types"));
|
package/build/modules/utils.d.ts
CHANGED
|
@@ -37,3 +37,4 @@ export declare function getValueByPath(obj: {
|
|
|
37
37
|
export declare function restoreHierarchy(obj: StringAnyType): StringAnyType;
|
|
38
38
|
export declare function isValidCron(cronExpression: string): boolean;
|
|
39
39
|
export declare const s: (input: string) => number;
|
|
40
|
+
export declare const arrayToHash: (response: [number, ...Array<string | string[]>]) => Record<string, string>[];
|
package/build/modules/utils.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.s = exports.isValidCron = exports.restoreHierarchy = exports.getValueByPath = exports.getIndexedHash = exports.getSymVal = exports.getSymKey = exports.formatISODate = exports.getTimeSeries = exports.getSubscriptionTopic = exports.findSubscriptionForTrigger = exports.findTopKey = exports.matchesStatus = exports.matchesStatusCode = exports.identifyRedisTypeFromClass = exports.polyfill = exports.identifyRedisType = exports.XSleepFor = exports.sleepImmediate = exports.sleepFor = exports.guid = exports.deterministicRandom = exports.deepCopy = exports.getSystemHealth = exports.hashOptions = void 0;
|
|
6
|
+
exports.arrayToHash = exports.s = exports.isValidCron = exports.restoreHierarchy = exports.getValueByPath = exports.getIndexedHash = exports.getSymVal = exports.getSymKey = exports.formatISODate = exports.getTimeSeries = exports.getSubscriptionTopic = exports.findSubscriptionForTrigger = exports.findTopKey = exports.matchesStatus = exports.matchesStatusCode = exports.identifyRedisTypeFromClass = exports.polyfill = exports.identifyRedisType = exports.XSleepFor = exports.sleepImmediate = exports.sleepFor = exports.guid = exports.deterministicRandom = exports.deepCopy = exports.getSystemHealth = exports.hashOptions = void 0;
|
|
7
7
|
const os_1 = __importDefault(require("os"));
|
|
8
8
|
const crypto_1 = require("crypto");
|
|
9
9
|
const nanoid_1 = require("nanoid");
|
|
@@ -240,3 +240,28 @@ const s = (input) => {
|
|
|
240
240
|
return (0, ms_1.default)(input) / 1000;
|
|
241
241
|
};
|
|
242
242
|
exports.s = s;
|
|
243
|
+
const arrayToHash = (response) => {
|
|
244
|
+
const results = [];
|
|
245
|
+
let key;
|
|
246
|
+
for (let i = 1; i < response.length; i++) {
|
|
247
|
+
const row = response[i];
|
|
248
|
+
const result = {};
|
|
249
|
+
if (Array.isArray(row)) {
|
|
250
|
+
for (let j = 0; j < row.length; j += 2) {
|
|
251
|
+
const key = row[j];
|
|
252
|
+
const value = row[j + 1];
|
|
253
|
+
result[key] = value;
|
|
254
|
+
}
|
|
255
|
+
if (key) {
|
|
256
|
+
result.$ = key;
|
|
257
|
+
}
|
|
258
|
+
results.push(result);
|
|
259
|
+
key = undefined;
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
key = row;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return results;
|
|
266
|
+
};
|
|
267
|
+
exports.arrayToHash = arrayToHash;
|
package/build/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hotmeshio/hotmesh",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "Unbreakable Workflows",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"test:cycle": "NODE_ENV=test jest ./tests/functional/cycle/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
29
29
|
"test:meshflow": "NODE_ENV=test jest ./tests/meshflow/*/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
30
30
|
"test:meshflow:basic": "NODE_ENV=test jest ./tests/meshflow/basic/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
31
|
-
"test:meshflow:collision": "NODE_ENV=test jest ./tests/meshflow/collision/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
31
|
+
"test:meshflow:collision": "NODE_ENV=test HMSH_LOGLEVEL=debug jest ./tests/meshflow/collision/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
32
32
|
"test:meshflow:fatal": "NODE_ENV=test jest ./tests/meshflow/fatal/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
33
33
|
"test:meshflow:goodbye": "NODE_ENV=test jest ./tests/meshflow/goodbye/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
34
34
|
"test:meshflow:hello": "HMSH_IS_CLUSTER=true NODE_ENV=test jest ./tests/meshflow/helloworld/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"test:sub:redis": "NODE_ENV=test jest ./tests/functional/sub/clients/redis.test.ts --detectOpenHandles --forceExit --verbose",
|
|
65
65
|
"test:trigger": "NODE_ENV=test jest ./tests/unit/services/activities/trigger.test.ts --detectOpenHandles --forceExit --verbose",
|
|
66
66
|
"test:meshdata": "NODE_ENV=test HMSH_IS_CLUSTER=true jest ./tests/meshdata/index.test.ts --forceExit --verbose --detectOpenHandles",
|
|
67
|
+
"test:meshos": "NODE_ENV=test HMSH_IS_CLUSTER=true jest ./tests/meshos/index.test.ts --forceExit --verbose --detectOpenHandles",
|
|
67
68
|
"test:meshcall": "NODE_ENV=test HMSH_LOGLEVEL=debug jest ./tests/meshcall/index.test.ts --forceExit --verbose --detectOpenHandles",
|
|
68
69
|
"test:unit": "NODE_ENV=test jest ./tests/unit/*/*/index.test.ts --detectOpenHandles --forceExit --verbose"
|
|
69
70
|
},
|
|
@@ -25,7 +25,6 @@ declare class Trigger extends Activity {
|
|
|
25
25
|
resolveJobId(context: Partial<JobState>): string;
|
|
26
26
|
resolveJobKey(context: Partial<JobState>): string;
|
|
27
27
|
setStateNX(status?: number): Promise<void>;
|
|
28
|
-
registerJobDependency(multi?: RedisMulti): Promise<void>;
|
|
29
28
|
setStats(multi?: RedisMulti): Promise<void>;
|
|
30
29
|
}
|
|
31
30
|
export { Trigger };
|
|
@@ -37,9 +37,6 @@ class Trigger extends activity_1.Activity {
|
|
|
37
37
|
if (options?.pending) {
|
|
38
38
|
await this.setExpired(options?.pending, multi);
|
|
39
39
|
}
|
|
40
|
-
else {
|
|
41
|
-
await this.registerJobDependency(multi);
|
|
42
|
-
}
|
|
43
40
|
await collator_1.CollatorService.notarizeInception(this, this.context.metadata.guid, multi);
|
|
44
41
|
await multi.exec();
|
|
45
42
|
this.execAdjacentParent();
|
|
@@ -228,35 +225,6 @@ class Trigger extends activity_1.Activity {
|
|
|
228
225
|
throw new errors_1.DuplicateJobError(jobId);
|
|
229
226
|
}
|
|
230
227
|
}
|
|
231
|
-
async registerJobDependency(multi) {
|
|
232
|
-
const depKey = this.config.stats?.parent ?? this.context.metadata.pj;
|
|
233
|
-
let resolvedDepKey = depKey ? pipe_1.Pipe.resolve(depKey, this.context) : '';
|
|
234
|
-
const adjKey = this.config.stats?.adjacent;
|
|
235
|
-
const resolvedAdjKey = depKey ? pipe_1.Pipe.resolve(adjKey, this.context) : '';
|
|
236
|
-
if (!resolvedDepKey) {
|
|
237
|
-
resolvedDepKey = this.context.metadata.pj;
|
|
238
|
-
}
|
|
239
|
-
if (resolvedDepKey) {
|
|
240
|
-
const isParentOrigin = resolvedDepKey === this.context.metadata.pj ||
|
|
241
|
-
resolvedDepKey === resolvedAdjKey;
|
|
242
|
-
let type;
|
|
243
|
-
if (isParentOrigin) {
|
|
244
|
-
if (this.context.metadata.px) {
|
|
245
|
-
type = 'child';
|
|
246
|
-
}
|
|
247
|
-
else {
|
|
248
|
-
type = 'expire-child';
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
type = 'expire';
|
|
253
|
-
}
|
|
254
|
-
await this.store.registerJobDependency(type, resolvedDepKey, this.context.metadata.tpc, this.context.metadata.jid, this.context.metadata.gid, this.context.metadata.pd, multi);
|
|
255
|
-
}
|
|
256
|
-
if (resolvedAdjKey && resolvedAdjKey !== resolvedDepKey) {
|
|
257
|
-
await this.store.registerJobDependency('child', resolvedAdjKey, this.context.metadata.tpc, this.context.metadata.jid, this.context.metadata.gid, this.context.metadata.pd, multi);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
228
|
async setStats(multi) {
|
|
261
229
|
const md = this.context.metadata;
|
|
262
230
|
if (md.key && this.config.stats?.measures) {
|
|
@@ -13,14 +13,11 @@ const exporter_1 = require("../exporter");
|
|
|
13
13
|
const reporter_1 = require("../reporter");
|
|
14
14
|
const router_1 = require("../router");
|
|
15
15
|
const serializer_1 = require("../serializer");
|
|
16
|
-
const redis_1 = require("../store/clients/redis");
|
|
17
|
-
const ioredis_1 = require("../store/clients/ioredis");
|
|
18
|
-
const redis_2 = require("../stream/clients/redis");
|
|
19
|
-
const ioredis_2 = require("../stream/clients/ioredis");
|
|
20
|
-
const ioredis_3 = require("../sub/clients/ioredis");
|
|
21
|
-
const redis_3 = require("../sub/clients/redis");
|
|
22
16
|
const task_1 = require("../task");
|
|
23
17
|
const stream_1 = require("../../types/stream");
|
|
18
|
+
const factory_1 = require("../stream/factory");
|
|
19
|
+
const factory_2 = require("../sub/factory");
|
|
20
|
+
const factory_3 = require("../store/factory");
|
|
24
21
|
class EngineService {
|
|
25
22
|
constructor() {
|
|
26
23
|
this.cacheMode = 'cache';
|
|
@@ -56,31 +53,13 @@ class EngineService {
|
|
|
56
53
|
}
|
|
57
54
|
}
|
|
58
55
|
async initStoreChannel(store) {
|
|
59
|
-
|
|
60
|
-
this.store = new redis_1.RedisStoreService(store);
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
this.store = new ioredis_1.IORedisStoreService(store);
|
|
64
|
-
}
|
|
65
|
-
await this.store.init(this.namespace, this.appId, this.logger);
|
|
56
|
+
this.store = await factory_3.StoreServiceFactory.init(store, this.namespace, this.appId, this.logger);
|
|
66
57
|
}
|
|
67
58
|
async initSubChannel(sub) {
|
|
68
|
-
|
|
69
|
-
this.subscribe = new redis_3.RedisSubService(sub);
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
this.subscribe = new ioredis_3.IORedisSubService(sub);
|
|
73
|
-
}
|
|
74
|
-
await this.subscribe.init(this.namespace, this.appId, this.guid, this.logger);
|
|
59
|
+
this.subscribe = await factory_2.SubServiceFactory.init(sub, this.namespace, this.appId, this.guid, this.logger);
|
|
75
60
|
}
|
|
76
61
|
async initStreamChannel(stream) {
|
|
77
|
-
|
|
78
|
-
this.stream = new redis_2.RedisStreamService(stream);
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
this.stream = new ioredis_2.IORedisStreamService(stream);
|
|
82
|
-
}
|
|
83
|
-
await this.stream.init(this.namespace, this.appId, this.logger);
|
|
62
|
+
this.stream = await factory_1.StreamServiceFactory.init(stream, this.namespace, this.appId, this.logger);
|
|
84
63
|
}
|
|
85
64
|
async initRouter(config) {
|
|
86
65
|
const throttle = await this.store.getThrottleRate(':');
|
|
@@ -53,7 +53,7 @@ class ClientService {
|
|
|
53
53
|
};
|
|
54
54
|
this.workflow = {
|
|
55
55
|
start: async (options) => {
|
|
56
|
-
const taskQueueName = options.
|
|
56
|
+
const taskQueueName = options.taskQueue ?? options.entity;
|
|
57
57
|
const workflowName = options.entity ?? options.workflowName;
|
|
58
58
|
const trc = options.workflowTrace;
|
|
59
59
|
const spn = options.workflowSpan;
|
|
@@ -86,7 +86,7 @@ class ClientService {
|
|
|
86
86
|
return await (await this.getHotMeshClient(topic, namespace)).hook(topic, { id: signalId, data });
|
|
87
87
|
},
|
|
88
88
|
hook: async (options) => {
|
|
89
|
-
const workflowTopic = `${options.taskQueue}-${options.workflowName}`;
|
|
89
|
+
const workflowTopic = `${options.taskQueue ?? options.entity}-${options.entity ?? options.workflowName}`;
|
|
90
90
|
const payload = {
|
|
91
91
|
arguments: [...options.args],
|
|
92
92
|
id: options.workflowId,
|
|
@@ -104,7 +104,9 @@ class Search {
|
|
|
104
104
|
return value;
|
|
105
105
|
}
|
|
106
106
|
catch (error) {
|
|
107
|
-
this.hotMeshClient.logger.error('meshflow-search-get-error', {
|
|
107
|
+
this.hotMeshClient.logger.error('meshflow-search-get-error', {
|
|
108
|
+
...error,
|
|
109
|
+
});
|
|
108
110
|
return '';
|
|
109
111
|
}
|
|
110
112
|
}
|
|
@@ -237,7 +237,7 @@ class WorkerService {
|
|
|
237
237
|
isProcessing = true;
|
|
238
238
|
const workflowInput = data.data;
|
|
239
239
|
const execIndex = counter.counter - interruptionRegistry.length + 1;
|
|
240
|
-
const { workflowId, workflowTopic, workflowDimension, originJobId, expire } = workflowInput;
|
|
240
|
+
const { workflowId, workflowTopic, workflowDimension, originJobId, expire, } = workflowInput;
|
|
241
241
|
const collatorFlowId = `${(0, utils_1.guid)()}$C`;
|
|
242
242
|
return {
|
|
243
243
|
status: stream_1.StreamStatus.SUCCESS,
|
|
@@ -116,7 +116,7 @@ class WorkflowService {
|
|
|
116
116
|
}
|
|
117
117
|
return result.$error;
|
|
118
118
|
}
|
|
119
|
-
else if (result
|
|
119
|
+
else if (!result?.$error) {
|
|
120
120
|
return result.data;
|
|
121
121
|
}
|
|
122
122
|
}
|
|
@@ -135,7 +135,7 @@ class WorkflowService {
|
|
|
135
135
|
childJobId = options.workflowId;
|
|
136
136
|
}
|
|
137
137
|
else if (options.entity) {
|
|
138
|
-
childJobId = `${options.entity}-${
|
|
138
|
+
childJobId = `${options.entity}-${(0, utils_1.guid)()}-${workflowDimension}-${execIndex}`;
|
|
139
139
|
}
|
|
140
140
|
else {
|
|
141
141
|
childJobId = `-${options.workflowName}-${(0, utils_1.guid)()}-${workflowDimension}-${execIndex}`;
|
|
@@ -283,7 +283,7 @@ class WorkflowService {
|
|
|
283
283
|
const targetWorkflowId = options.workflowId ?? workflowId;
|
|
284
284
|
let targetTopic;
|
|
285
285
|
if (options.entity || (options.taskQueue && options.workflowName)) {
|
|
286
|
-
targetTopic = `${options.
|
|
286
|
+
targetTopic = `${options.taskQueue ?? options.entity}-${options.entity ?? options.workflowName}`;
|
|
287
287
|
}
|
|
288
288
|
else {
|
|
289
289
|
targetTopic = workflowTopic;
|
|
@@ -291,8 +291,10 @@ class WorkflowService {
|
|
|
291
291
|
const payload = {
|
|
292
292
|
arguments: [...options.args],
|
|
293
293
|
id: targetWorkflowId,
|
|
294
|
-
workflowTopic,
|
|
294
|
+
workflowTopic: targetTopic,
|
|
295
295
|
backoffCoefficient: options.config?.backoffCoefficient || enums_1.HMSH_MESHFLOW_EXP_BACKOFF,
|
|
296
|
+
maximumAttempts: options.config?.maximumAttempts || enums_1.HMSH_MESHFLOW_MAX_ATTEMPTS,
|
|
297
|
+
maximumInterval: (0, utils_1.s)(options?.config?.maximumInterval ?? enums_1.HMSH_MESHFLOW_MAX_INTERVAL),
|
|
296
298
|
};
|
|
297
299
|
return await hotMeshClient.hook(`${namespace}.flow.signal`, payload, stream_1.StreamStatus.PENDING, 202);
|
|
298
300
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { MeshData } from '../meshdata/index';
|
|
2
|
+
import * as Types from '../../types';
|
|
3
|
+
declare abstract class MeshOS {
|
|
4
|
+
meshData: MeshData;
|
|
5
|
+
connected: boolean;
|
|
6
|
+
namespace: string;
|
|
7
|
+
namespaceType: string;
|
|
8
|
+
static databases: Record<string, Types.DB>;
|
|
9
|
+
static namespaces: Types.Namespaces;
|
|
10
|
+
static entities: Record<string, Types.Entity>;
|
|
11
|
+
static schemas: Record<string, Types.WorkflowSearchSchema>;
|
|
12
|
+
static profiles: Types.Profiles;
|
|
13
|
+
static classes: Record<string, typeof MeshOS>;
|
|
14
|
+
static logger: Types.ILogger;
|
|
15
|
+
constructor(namespace: string, namespaceType: string, config: Types.DBConfig);
|
|
16
|
+
protected abstract getEntity(): string;
|
|
17
|
+
abstract getSearchOptions(): Types.WorkflowSearchOptions;
|
|
18
|
+
protected abstract getTaskQueue(): string;
|
|
19
|
+
private initializeMeshData;
|
|
20
|
+
protected defaultTargetFn(): Promise<string>;
|
|
21
|
+
getNamespace(): string;
|
|
22
|
+
getRedisUrl: (config: Types.DBConfig) => {
|
|
23
|
+
url: string;
|
|
24
|
+
};
|
|
25
|
+
connect(): Promise<void>;
|
|
26
|
+
index(): Promise<void>;
|
|
27
|
+
static shutdown(): Promise<void>;
|
|
28
|
+
getIndexName(): string;
|
|
29
|
+
create(body: Record<string, any>): Promise<Types.StringStringType>;
|
|
30
|
+
retrieve(id: string, sparse?: boolean): Promise<Types.StringStringType>;
|
|
31
|
+
update(id: string, body: Record<string, any>): Promise<Types.StringStringType>;
|
|
32
|
+
delete(id: string): Promise<boolean>;
|
|
33
|
+
find(query?: {
|
|
34
|
+
field: string;
|
|
35
|
+
is: '=' | '[]' | '>=' | '<=';
|
|
36
|
+
value: string;
|
|
37
|
+
}[], start?: number, size?: number): Promise<{
|
|
38
|
+
count: number;
|
|
39
|
+
query: string;
|
|
40
|
+
data: Types.StringStringType[];
|
|
41
|
+
}>;
|
|
42
|
+
count(query: {
|
|
43
|
+
field: string;
|
|
44
|
+
is: '=' | '[]' | '>=' | '<=';
|
|
45
|
+
value: string;
|
|
46
|
+
}[]): Promise<number>;
|
|
47
|
+
aggregate(filter?: {
|
|
48
|
+
field: string;
|
|
49
|
+
is: '=' | '[]' | '>=' | '<=';
|
|
50
|
+
value: string;
|
|
51
|
+
}[], apply?: {
|
|
52
|
+
expression: string;
|
|
53
|
+
as: string;
|
|
54
|
+
}[], rows?: string[], columns?: string[], reduce?: {
|
|
55
|
+
operation: string;
|
|
56
|
+
as: string;
|
|
57
|
+
property?: string;
|
|
58
|
+
}[], sort?: {
|
|
59
|
+
field: string;
|
|
60
|
+
order: 'ASC' | 'DESC';
|
|
61
|
+
}[], start?: number, size?: number): Promise<{
|
|
62
|
+
count: number;
|
|
63
|
+
query: string;
|
|
64
|
+
data: Types.StringStringType[];
|
|
65
|
+
}>;
|
|
66
|
+
private buildAggregateCommand;
|
|
67
|
+
private buildFilterCommand;
|
|
68
|
+
init(search?: boolean): Promise<void>;
|
|
69
|
+
static registerDatabase(id: string, config: Types.DB): void;
|
|
70
|
+
static registerNamespace(id: string, config: Types.Namespace): void;
|
|
71
|
+
static registerEntity(id: string, config: Types.Entity): void;
|
|
72
|
+
static registerSchema(id: string, schema: Types.WorkflowSearchSchema): void;
|
|
73
|
+
static registerProfile(id: string, config: Types.Profile): void;
|
|
74
|
+
static registerClass(id: string, entityClass: typeof MeshOS): void;
|
|
75
|
+
static init(p?: Types.Profiles): Promise<void>;
|
|
76
|
+
static findEntity(database: string, namespace: string, entity: string): Types.EntityInstanceTypes | undefined;
|
|
77
|
+
static findSchemas(database: string, ns: string): Record<string, Types.WorkflowSearchSchema>;
|
|
78
|
+
static toJSON(p?: Types.Profiles): any;
|
|
79
|
+
workflow: {};
|
|
80
|
+
}
|
|
81
|
+
export { MeshOS };
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.MeshOS = void 0;
|
|
27
|
+
const Redis = __importStar(require("redis"));
|
|
28
|
+
const index_1 = require("../meshdata/index");
|
|
29
|
+
const utils_1 = require("../../modules/utils");
|
|
30
|
+
const logger_1 = require("../logger");
|
|
31
|
+
class MeshOS {
|
|
32
|
+
constructor(namespace, namespaceType, config) {
|
|
33
|
+
this.connected = false;
|
|
34
|
+
this.getRedisUrl = (config) => {
|
|
35
|
+
return {
|
|
36
|
+
url: `redis${config.REDIS_USE_TLS ? 's' : ''}://${config.REDIS_USERNAME ?? ''}:${config.REDIS_PASSWORD}@${config.REDIS_HOST}:${config.REDIS_PORT}`,
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
this.workflow = {};
|
|
40
|
+
this.namespace = namespace;
|
|
41
|
+
this.namespaceType = namespaceType;
|
|
42
|
+
this.meshData = this.initializeMeshData(config);
|
|
43
|
+
}
|
|
44
|
+
initializeMeshData(dbConfig) {
|
|
45
|
+
return new index_1.MeshData(Redis, this.getRedisUrl(dbConfig), this.getSearchOptions());
|
|
46
|
+
}
|
|
47
|
+
async defaultTargetFn() {
|
|
48
|
+
return 'OK';
|
|
49
|
+
}
|
|
50
|
+
getNamespace() {
|
|
51
|
+
return this.namespace;
|
|
52
|
+
}
|
|
53
|
+
async connect() {
|
|
54
|
+
this.connected = await this.meshData.connect({
|
|
55
|
+
entity: this.getEntity(),
|
|
56
|
+
target: this.defaultTargetFn,
|
|
57
|
+
options: {
|
|
58
|
+
namespace: this.getNamespace(),
|
|
59
|
+
taskQueue: this.getTaskQueue(),
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
async index() {
|
|
64
|
+
await this.meshData.createSearchIndex(this.getEntity(), { namespace: this.getNamespace() }, this.getSearchOptions());
|
|
65
|
+
}
|
|
66
|
+
static async shutdown() {
|
|
67
|
+
await index_1.MeshData.shutdown();
|
|
68
|
+
}
|
|
69
|
+
getIndexName() {
|
|
70
|
+
return this.getSearchOptions().index;
|
|
71
|
+
}
|
|
72
|
+
async create(body) {
|
|
73
|
+
const id = body.id || (0, utils_1.guid)();
|
|
74
|
+
await this.meshData.set(this.getEntity(), id, {
|
|
75
|
+
search: { data: body },
|
|
76
|
+
namespace: this.getNamespace(),
|
|
77
|
+
});
|
|
78
|
+
return this.retrieve(id);
|
|
79
|
+
}
|
|
80
|
+
async retrieve(id, sparse = false) {
|
|
81
|
+
const opts = this.getSearchOptions();
|
|
82
|
+
const fields = sparse ? ['id'] : Object.keys(opts?.schema || {});
|
|
83
|
+
const result = await this.meshData.get(this.getEntity(), id, {
|
|
84
|
+
fields,
|
|
85
|
+
namespace: this.getNamespace(),
|
|
86
|
+
});
|
|
87
|
+
if (!result?.id)
|
|
88
|
+
throw new Error(`${this.getEntity()} not found`);
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
async update(id, body) {
|
|
92
|
+
await this.retrieve(id);
|
|
93
|
+
await this.meshData.set(this.getEntity(), id, {
|
|
94
|
+
search: { data: body },
|
|
95
|
+
namespace: this.getNamespace(),
|
|
96
|
+
});
|
|
97
|
+
return this.retrieve(id);
|
|
98
|
+
}
|
|
99
|
+
async delete(id) {
|
|
100
|
+
await this.retrieve(id);
|
|
101
|
+
await this.meshData.flush(this.getEntity(), id, this.getNamespace());
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
async find(query = [], start = 0, size = 100) {
|
|
105
|
+
const opts = this.getSearchOptions();
|
|
106
|
+
return this.meshData.findWhere(this.getEntity(), {
|
|
107
|
+
query,
|
|
108
|
+
return: Object.keys(opts?.schema || {}),
|
|
109
|
+
limit: { start, size },
|
|
110
|
+
options: { namespace: this.getNamespace() },
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
async count(query) {
|
|
114
|
+
return this.meshData.findWhere(this.getEntity(), {
|
|
115
|
+
query,
|
|
116
|
+
count: true,
|
|
117
|
+
options: { namespace: this.getNamespace() },
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
async aggregate(filter = [], apply = [], rows = [], columns = [], reduce = [], sort = [], start = 0, size = 100) {
|
|
121
|
+
const command = this.buildAggregateCommand(filter, apply, rows, columns, reduce, sort);
|
|
122
|
+
try {
|
|
123
|
+
const results = await this.meshData.find(this.getEntity(), {
|
|
124
|
+
index: this.getIndexName(),
|
|
125
|
+
namespace: this.getNamespace(),
|
|
126
|
+
taskQueue: this.getTaskQueue(),
|
|
127
|
+
search: this.getSearchOptions(),
|
|
128
|
+
}, ...command);
|
|
129
|
+
return {
|
|
130
|
+
count: results[0],
|
|
131
|
+
query: command.join(' '),
|
|
132
|
+
data: (0, utils_1.arrayToHash)(results),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
throw e;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
buildAggregateCommand(filter, apply, rows, columns, reduce, sort) {
|
|
140
|
+
const command = ['FT.AGGREGATE', this.getIndexName() || 'default'];
|
|
141
|
+
const opts = this.getSearchOptions();
|
|
142
|
+
command.push(this.buildFilterCommand(filter));
|
|
143
|
+
apply.forEach((a) => command.push('APPLY', a.expression, 'AS', a.as));
|
|
144
|
+
const groupBy = rows.concat(columns);
|
|
145
|
+
if (groupBy.length > 0) {
|
|
146
|
+
command.push('GROUPBY', `${groupBy.length}`, ...groupBy.map((g) => opts?.schema?.[g] ? `@_${g}` : `@${g}`));
|
|
147
|
+
}
|
|
148
|
+
reduce.forEach((r) => {
|
|
149
|
+
const op = r.operation.toUpperCase();
|
|
150
|
+
if (op === 'COUNT') {
|
|
151
|
+
command.push('REDUCE', op, '0', 'AS', r.as ?? 'count');
|
|
152
|
+
}
|
|
153
|
+
else if ([
|
|
154
|
+
'COUNT_DISTINCT',
|
|
155
|
+
'COUNT_DISTINCTISH',
|
|
156
|
+
'SUM',
|
|
157
|
+
'AVG',
|
|
158
|
+
'MIN',
|
|
159
|
+
'MAX',
|
|
160
|
+
'STDDEV',
|
|
161
|
+
'TOLIST',
|
|
162
|
+
].includes(op)) {
|
|
163
|
+
const property = r.property
|
|
164
|
+
? opts?.schema?.[r.property]
|
|
165
|
+
? `@_${r.property}`
|
|
166
|
+
: `@${r.property}`
|
|
167
|
+
: '';
|
|
168
|
+
command.push('REDUCE', op, '1', property, 'AS', r.as ?? `${r.operation}_${r.property}`);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
if (sort.length > 0) {
|
|
172
|
+
command.push('SORTBY', `${2 * sort.length}`, ...sort.flatMap((s) => [
|
|
173
|
+
opts?.schema?.[s.field] ? `@_${s.field}` : `@${s.field}`,
|
|
174
|
+
s.order.toUpperCase() || 'DESC',
|
|
175
|
+
]));
|
|
176
|
+
}
|
|
177
|
+
return command;
|
|
178
|
+
}
|
|
179
|
+
buildFilterCommand(filter) {
|
|
180
|
+
if (filter.length === 0)
|
|
181
|
+
return '*';
|
|
182
|
+
const opts = this.getSearchOptions();
|
|
183
|
+
return filter
|
|
184
|
+
.map((q) => {
|
|
185
|
+
const type = opts?.schema?.[q.field]?.type ?? 'TEXT';
|
|
186
|
+
switch (type) {
|
|
187
|
+
case 'TAG':
|
|
188
|
+
return `@_${q.field}:{${q.value}}`;
|
|
189
|
+
case 'TEXT':
|
|
190
|
+
return `@_${q.field}:${q.value}`;
|
|
191
|
+
case 'NUMERIC':
|
|
192
|
+
return `@_${q.field}:[${q.value}]`;
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
.join(' ');
|
|
196
|
+
}
|
|
197
|
+
async init(search = true) {
|
|
198
|
+
await this.connect();
|
|
199
|
+
if (search) {
|
|
200
|
+
await this.index();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
static registerDatabase(id, config) {
|
|
204
|
+
MeshOS.databases[id] = config;
|
|
205
|
+
}
|
|
206
|
+
static registerNamespace(id, config) {
|
|
207
|
+
MeshOS.namespaces[id] = config;
|
|
208
|
+
}
|
|
209
|
+
static registerEntity(id, config) {
|
|
210
|
+
MeshOS.entities[id] = config;
|
|
211
|
+
}
|
|
212
|
+
static registerSchema(id, schema) {
|
|
213
|
+
MeshOS.schemas[id] = schema;
|
|
214
|
+
}
|
|
215
|
+
static registerProfile(id, config) {
|
|
216
|
+
MeshOS.profiles[id] = config;
|
|
217
|
+
}
|
|
218
|
+
static registerClass(id, entityClass) {
|
|
219
|
+
MeshOS.classes[id] = entityClass;
|
|
220
|
+
}
|
|
221
|
+
static async init(p = MeshOS.profiles) {
|
|
222
|
+
for (const key in p) {
|
|
223
|
+
const profile = p[key];
|
|
224
|
+
if (profile.db.config.REDIS_HOST) {
|
|
225
|
+
this.logger.info(`meshos-initializing`, {
|
|
226
|
+
db: profile.db.name,
|
|
227
|
+
key,
|
|
228
|
+
});
|
|
229
|
+
profile.instances = {};
|
|
230
|
+
for (const ns in profile.namespaces) {
|
|
231
|
+
const namespace = profile.namespaces[ns];
|
|
232
|
+
this.logger.info(`meshos-initializing-namespace`, {
|
|
233
|
+
namespace: ns,
|
|
234
|
+
label: namespace.label,
|
|
235
|
+
});
|
|
236
|
+
let pinstances = profile.instances[ns];
|
|
237
|
+
if (!pinstances) {
|
|
238
|
+
pinstances = {};
|
|
239
|
+
profile.instances[ns] = pinstances;
|
|
240
|
+
}
|
|
241
|
+
for (const entity of namespace.entities) {
|
|
242
|
+
this.logger.info(`meshos-initializing-entity`, {
|
|
243
|
+
entity: entity.name,
|
|
244
|
+
label: entity.label,
|
|
245
|
+
});
|
|
246
|
+
const instance = pinstances[entity.name] = new entity.class(ns, namespace.type, profile.db.config);
|
|
247
|
+
await instance.init(profile.db.search);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
static findEntity(database, namespace, entity) {
|
|
254
|
+
if (!database ||
|
|
255
|
+
!MeshOS.profiles[database] ||
|
|
256
|
+
!MeshOS.profiles[database]?.db?.config?.REDIS_HOST) {
|
|
257
|
+
const activeProfiles = Object.keys(MeshOS.profiles).filter((key) => MeshOS.profiles[key]?.db?.config?.REDIS_HOST);
|
|
258
|
+
throw new Error(`The database query parameter [${database}] was not found. Use one of: ${activeProfiles.join(', ')}`);
|
|
259
|
+
}
|
|
260
|
+
if (!namespace || !MeshOS.profiles[database]?.instances?.[namespace]) {
|
|
261
|
+
const activeNamespaces = Object.keys(MeshOS.profiles[database]?.instances ?? {});
|
|
262
|
+
throw new Error(`The namespace query parameter [${namespace}] was not found. Use one of: ${activeNamespaces.join(', ')}`);
|
|
263
|
+
}
|
|
264
|
+
const entities = MeshOS.profiles[database]?.instances?.[namespace] ?? {};
|
|
265
|
+
if (!entity || entity?.startsWith('-') || entity === '*') {
|
|
266
|
+
entity = Object.keys(entities)[0];
|
|
267
|
+
}
|
|
268
|
+
else if (entity?.endsWith('*')) {
|
|
269
|
+
entity = entity.slice(0, -1);
|
|
270
|
+
}
|
|
271
|
+
const target = MeshOS.profiles[database]?.instances?.[namespace]?.[entity];
|
|
272
|
+
if (!target) {
|
|
273
|
+
this.logger.error(`meshos-entity-not-found`, {
|
|
274
|
+
database,
|
|
275
|
+
namespace,
|
|
276
|
+
entity,
|
|
277
|
+
});
|
|
278
|
+
entity = Object.keys(entities)[0];
|
|
279
|
+
return MeshOS.profiles[database]?.instances?.[namespace]?.[entity];
|
|
280
|
+
}
|
|
281
|
+
return target;
|
|
282
|
+
}
|
|
283
|
+
static findSchemas(database, ns) {
|
|
284
|
+
if (!database ||
|
|
285
|
+
!MeshOS.profiles[database] ||
|
|
286
|
+
!MeshOS.profiles[database]?.db?.config?.REDIS_HOST) {
|
|
287
|
+
const activeProfiles = Object.keys(MeshOS.profiles).filter((key) => MeshOS.profiles[key]?.db?.config?.REDIS_HOST);
|
|
288
|
+
throw new Error(`The database query parameter [${database}] was not found. Use one of: ${activeProfiles.join(', ')}`);
|
|
289
|
+
}
|
|
290
|
+
const profile = MeshOS.profiles[database];
|
|
291
|
+
const namespacedInstance = profile.instances[ns];
|
|
292
|
+
const schemas = {};
|
|
293
|
+
for (const entityName in namespacedInstance) {
|
|
294
|
+
const entityInstance = namespacedInstance[entityName];
|
|
295
|
+
const opts = entityInstance.getSearchOptions();
|
|
296
|
+
schemas[opts.index ?? entityName] = opts.schema;
|
|
297
|
+
}
|
|
298
|
+
return schemas;
|
|
299
|
+
}
|
|
300
|
+
static toJSON(p = MeshOS.profiles) {
|
|
301
|
+
const result = {};
|
|
302
|
+
for (const key in p) {
|
|
303
|
+
const profile = p[key];
|
|
304
|
+
if (!profile.db.config.REDIS_HOST) {
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
result[key] = {
|
|
309
|
+
db: { ...profile.db, config: undefined },
|
|
310
|
+
namespaces: {},
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
for (const ns in profile.namespaces) {
|
|
314
|
+
const namespace = profile.namespaces[ns];
|
|
315
|
+
result[key].namespaces[ns] = {
|
|
316
|
+
name: namespace.name,
|
|
317
|
+
label: namespace.label,
|
|
318
|
+
entities: [],
|
|
319
|
+
};
|
|
320
|
+
for (const entity of namespace.entities) {
|
|
321
|
+
result[key].namespaces[ns].entities.push({
|
|
322
|
+
name: entity.name,
|
|
323
|
+
label: entity.label,
|
|
324
|
+
schema: entity.schema,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return result;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
exports.MeshOS = MeshOS;
|
|
333
|
+
MeshOS.databases = {};
|
|
334
|
+
MeshOS.namespaces = {};
|
|
335
|
+
MeshOS.entities = {};
|
|
336
|
+
MeshOS.schemas = {};
|
|
337
|
+
MeshOS.profiles = {};
|
|
338
|
+
MeshOS.classes = {};
|
|
339
|
+
MeshOS.logger = new logger_1.LoggerService('hotmesh', 'meshos');
|
|
@@ -4,11 +4,9 @@ exports.QuorumService = void 0;
|
|
|
4
4
|
const enums_1 = require("../../modules/enums");
|
|
5
5
|
const utils_1 = require("../../modules/utils");
|
|
6
6
|
const compiler_1 = require("../compiler");
|
|
7
|
-
const ioredis_1 = require("../store/clients/ioredis");
|
|
8
|
-
const redis_1 = require("../store/clients/redis");
|
|
9
|
-
const ioredis_2 = require("../sub/clients/ioredis");
|
|
10
|
-
const redis_2 = require("../sub/clients/redis");
|
|
11
7
|
const hotmesh_1 = require("../../types/hotmesh");
|
|
8
|
+
const factory_1 = require("../sub/factory");
|
|
9
|
+
const factory_2 = require("../store/factory");
|
|
12
10
|
class QuorumService {
|
|
13
11
|
constructor() {
|
|
14
12
|
this.profiles = [];
|
|
@@ -42,22 +40,10 @@ class QuorumService {
|
|
|
42
40
|
}
|
|
43
41
|
}
|
|
44
42
|
async initStoreChannel(store) {
|
|
45
|
-
|
|
46
|
-
this.store = new redis_1.RedisStoreService(store);
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
this.store = new ioredis_1.IORedisStoreService(store);
|
|
50
|
-
}
|
|
51
|
-
await this.store.init(this.namespace, this.appId, this.logger);
|
|
43
|
+
this.store = await factory_2.StoreServiceFactory.init(store, this.namespace, this.appId, this.logger);
|
|
52
44
|
}
|
|
53
45
|
async initSubChannel(sub) {
|
|
54
|
-
|
|
55
|
-
this.subscribe = new redis_2.RedisSubService(sub);
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
this.subscribe = new ioredis_2.IORedisSubService(sub);
|
|
59
|
-
}
|
|
60
|
-
await this.subscribe.init(this.namespace, this.appId, this.guid, this.logger);
|
|
46
|
+
this.subscribe = await factory_1.SubServiceFactory.init(sub, this.namespace, this.appId, this.guid, this.logger);
|
|
61
47
|
}
|
|
62
48
|
subscriptionHandler() {
|
|
63
49
|
const self = this;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { RedisClient } from '../../types/redis';
|
|
2
|
+
import { ILogger } from '../logger';
|
|
3
|
+
import { StoreService } from './index';
|
|
4
|
+
declare class StoreServiceFactory {
|
|
5
|
+
static init(redisClient: RedisClient, namespace: string, appId: string, logger: ILogger): Promise<StoreService<any, any>>;
|
|
6
|
+
}
|
|
7
|
+
export { StoreServiceFactory };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StoreServiceFactory = void 0;
|
|
4
|
+
const utils_1 = require("../../modules/utils");
|
|
5
|
+
const ioredis_1 = require("./clients/ioredis");
|
|
6
|
+
const redis_1 = require("./clients/redis");
|
|
7
|
+
class StoreServiceFactory {
|
|
8
|
+
static async init(redisClient, namespace, appId, logger) {
|
|
9
|
+
let service;
|
|
10
|
+
if ((0, utils_1.identifyRedisType)(redisClient) === 'redis') {
|
|
11
|
+
service = new redis_1.RedisStoreService(redisClient);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
service = new ioredis_1.IORedisStoreService(redisClient);
|
|
15
|
+
}
|
|
16
|
+
await service.init(namespace, appId, logger);
|
|
17
|
+
return service;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.StoreServiceFactory = StoreServiceFactory;
|
|
@@ -61,7 +61,6 @@ declare abstract class StoreService<T, U extends AbstractRedisClient> {
|
|
|
61
61
|
setApp(id: string, version: string): Promise<HotMeshApp>;
|
|
62
62
|
activateAppVersion(id: string, version: string): Promise<boolean>;
|
|
63
63
|
registerAppVersion(appId: string, version: string): Promise<any>;
|
|
64
|
-
registerJobDependency(depType: WorkListTaskType, originJobId: string, topic: string, jobId: string, gId: string, pd?: string, multi?: U): Promise<any>;
|
|
65
64
|
setStats(jobKey: string, jobId: string, dateTime: string, stats: StatsType, appVersion: AppVID, multi?: U): Promise<any>;
|
|
66
65
|
hGetAllResult(result: any): any;
|
|
67
66
|
getJobStats(jobKeys: string[]): Promise<JobStatsRange>;
|
|
@@ -355,8 +355,6 @@ class StoreService {
|
|
|
355
355
|
};
|
|
356
356
|
return await this.redisClient[this.commands.hset](key, payload);
|
|
357
357
|
}
|
|
358
|
-
async registerJobDependency(depType, originJobId, topic, jobId, gId, pd = '', multi) {
|
|
359
|
-
}
|
|
360
358
|
async setStats(jobKey, jobId, dateTime, stats, appVersion, multi) {
|
|
361
359
|
const params = {
|
|
362
360
|
appId: appVersion.id,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { RedisClient } from '../../types/redis';
|
|
2
|
+
import { ILogger } from '../logger';
|
|
3
|
+
import { StreamService } from './index';
|
|
4
|
+
declare class StreamServiceFactory {
|
|
5
|
+
static init(redisClient: RedisClient, namespace: string, appId: string, logger: ILogger): Promise<StreamService<any, any>>;
|
|
6
|
+
}
|
|
7
|
+
export { StreamServiceFactory };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StreamServiceFactory = void 0;
|
|
4
|
+
const utils_1 = require("../../modules/utils");
|
|
5
|
+
const ioredis_1 = require("./clients/ioredis");
|
|
6
|
+
const redis_1 = require("./clients/redis");
|
|
7
|
+
class StreamServiceFactory {
|
|
8
|
+
static async init(redisClient, namespace, appId, logger) {
|
|
9
|
+
let service;
|
|
10
|
+
if ((0, utils_1.identifyRedisType)(redisClient) === 'redis') {
|
|
11
|
+
service = new redis_1.RedisStreamService(redisClient);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
service = new ioredis_1.IORedisStreamService(redisClient);
|
|
15
|
+
}
|
|
16
|
+
await service.init(namespace, appId, logger);
|
|
17
|
+
return service;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.StreamServiceFactory = StreamServiceFactory;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { RedisClient } from '../../types/redis';
|
|
2
|
+
import { ILogger } from '../logger';
|
|
3
|
+
import { SubService } from './index';
|
|
4
|
+
declare class SubServiceFactory {
|
|
5
|
+
static init(redisClient: RedisClient, namespace: string, appId: string, engineId: string, logger: ILogger): Promise<SubService<any, any>>;
|
|
6
|
+
}
|
|
7
|
+
export { SubServiceFactory };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SubServiceFactory = void 0;
|
|
4
|
+
const utils_1 = require("../../modules/utils");
|
|
5
|
+
const ioredis_1 = require("./clients/ioredis");
|
|
6
|
+
const redis_1 = require("./clients/redis");
|
|
7
|
+
class SubServiceFactory {
|
|
8
|
+
static async init(redisClient, namespace, appId, engineId, logger) {
|
|
9
|
+
let service;
|
|
10
|
+
if ((0, utils_1.identifyRedisType)(redisClient) === 'redis') {
|
|
11
|
+
service = new redis_1.RedisSubService(redisClient);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
service = new ioredis_1.IORedisSubService(redisClient);
|
|
15
|
+
}
|
|
16
|
+
await service.init(namespace, appId, engineId, logger);
|
|
17
|
+
return service;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.SubServiceFactory = SubServiceFactory;
|
|
@@ -5,14 +5,11 @@ const key_1 = require("../../modules/key");
|
|
|
5
5
|
const utils_1 = require("../../modules/utils");
|
|
6
6
|
const connector_1 = require("../connector");
|
|
7
7
|
const router_1 = require("../router");
|
|
8
|
-
const ioredis_1 = require("../store/clients/ioredis");
|
|
9
|
-
const redis_1 = require("../store/clients/redis");
|
|
10
|
-
const ioredis_2 = require("../stream/clients/ioredis");
|
|
11
|
-
const redis_2 = require("../stream/clients/redis");
|
|
12
|
-
const ioredis_3 = require("../sub/clients/ioredis");
|
|
13
|
-
const redis_3 = require("../sub/clients/redis");
|
|
14
8
|
const stream_1 = require("../../types/stream");
|
|
15
9
|
const enums_1 = require("../../modules/enums");
|
|
10
|
+
const factory_1 = require("../stream/factory");
|
|
11
|
+
const factory_2 = require("../sub/factory");
|
|
12
|
+
const factory_3 = require("../store/factory");
|
|
16
13
|
class WorkerService {
|
|
17
14
|
constructor() {
|
|
18
15
|
this.reporting = false;
|
|
@@ -58,31 +55,13 @@ class WorkerService {
|
|
|
58
55
|
}
|
|
59
56
|
}
|
|
60
57
|
async initStoreChannel(service, store) {
|
|
61
|
-
|
|
62
|
-
service.store = new redis_1.RedisStoreService(store);
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
service.store = new ioredis_1.IORedisStoreService(store);
|
|
66
|
-
}
|
|
67
|
-
await service.store.init(service.namespace, service.appId, service.logger);
|
|
58
|
+
service.store = await factory_3.StoreServiceFactory.init(store, service.namespace, service.appId, service.logger);
|
|
68
59
|
}
|
|
69
60
|
async initSubChannel(service, sub) {
|
|
70
|
-
|
|
71
|
-
service.subscribe = new redis_3.RedisSubService(sub);
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
service.subscribe = new ioredis_3.IORedisSubService(sub);
|
|
75
|
-
}
|
|
76
|
-
await service.subscribe.init(service.namespace, service.appId, service.guid, service.logger);
|
|
61
|
+
service.subscribe = await factory_2.SubServiceFactory.init(sub, service.namespace, service.appId, service.guid, service.logger);
|
|
77
62
|
}
|
|
78
63
|
async initStreamChannel(service, stream) {
|
|
79
|
-
|
|
80
|
-
service.stream = new redis_2.RedisStreamService(stream);
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
service.stream = new ioredis_2.IORedisStreamService(stream);
|
|
84
|
-
}
|
|
85
|
-
await service.stream.init(service.namespace, service.appId, service.logger);
|
|
64
|
+
service.stream = await factory_1.StreamServiceFactory.init(stream, service.namespace, service.appId, service.logger);
|
|
86
65
|
}
|
|
87
66
|
async initRouter(worker, logger) {
|
|
88
67
|
const throttle = await this.store.getThrottleRate(worker.topic);
|
package/build/types/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export { ActivityAction, DependencyExport, MeshFlowJobExport, ExportCycles, Expo
|
|
|
9
9
|
export { HookCondition, HookConditions, HookGate, HookInterface, HookRule, HookRules, HookSignal, } from './hook';
|
|
10
10
|
export { ILogger, LogLevel } from './logger';
|
|
11
11
|
export { ExtensionType, JobCompletionOptions, JobData, JobsData, JobInterruptOptions, JobMetadata, JobOutput, JobState, JobStatus, PartialJobState, } from './job';
|
|
12
|
+
export { DB, DBConfig, Profile, Namespaces, Entity, EntityInstanceTypes, SubClassInstance, AllSubclassInstances, SubclassType, Namespace, Instance, Instances, Profiles, } from './manifest';
|
|
12
13
|
export { MappingStatements } from './map';
|
|
13
14
|
export { Pipe, PipeContext, PipeItem, PipeItems, PipeObject, ReduceObject, } from './pipe';
|
|
14
15
|
export { HotMesh, HotMeshApp, HotMeshApps, HotMeshConfig, HotMeshEngine, RedisConfig, HotMeshGraph, HotMeshManifest, HotMeshSettings, HotMeshWorker, KeyStoreParams, KeyType, } from './hotmesh';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { MeshOS } from '../services/meshos';
|
|
2
|
+
import * as Types from './index';
|
|
3
|
+
export type DBConfig = {
|
|
4
|
+
REDIS_DATABASE: number;
|
|
5
|
+
REDIS_HOST: string | undefined;
|
|
6
|
+
REDIS_PORT: number;
|
|
7
|
+
REDIS_USERNAME: string;
|
|
8
|
+
REDIS_PASSWORD: string;
|
|
9
|
+
REDIS_USE_TLS: boolean;
|
|
10
|
+
};
|
|
11
|
+
export type DB = {
|
|
12
|
+
name: string;
|
|
13
|
+
label: string;
|
|
14
|
+
search: boolean;
|
|
15
|
+
config: DBConfig;
|
|
16
|
+
};
|
|
17
|
+
export type SubClassInstance<T extends typeof MeshOS> = T extends abstract new (...args: any) => infer R ? R : never;
|
|
18
|
+
export type AllSubclassInstances = SubClassInstance<(typeof MeshOS)['classes'][keyof (typeof MeshOS)['classes']]>;
|
|
19
|
+
export type EntityInstanceTypes = MeshOS;
|
|
20
|
+
export type SubclassType<T extends MeshOS = MeshOS> = new (...args: any[]) => T;
|
|
21
|
+
export type Entity = {
|
|
22
|
+
name: string;
|
|
23
|
+
label: string;
|
|
24
|
+
schema: Types.WorkflowSearchSchema;
|
|
25
|
+
class: SubclassType;
|
|
26
|
+
};
|
|
27
|
+
export type Namespace = {
|
|
28
|
+
name: string;
|
|
29
|
+
type: string;
|
|
30
|
+
label: string;
|
|
31
|
+
entities: Entity[];
|
|
32
|
+
};
|
|
33
|
+
export type Namespaces = {
|
|
34
|
+
[key: string]: Namespace;
|
|
35
|
+
};
|
|
36
|
+
export type Instance = {
|
|
37
|
+
[key: string]: EntityInstanceTypes;
|
|
38
|
+
};
|
|
39
|
+
export type Instances = {
|
|
40
|
+
[key: string]: Instance;
|
|
41
|
+
};
|
|
42
|
+
export type Profile = {
|
|
43
|
+
db: DB;
|
|
44
|
+
namespaces: Namespaces;
|
|
45
|
+
instances?: Instances;
|
|
46
|
+
};
|
|
47
|
+
export type Profiles = {
|
|
48
|
+
[key: string]: Profile;
|
|
49
|
+
};
|
package/index.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { MeshCall } from './services/meshcall';
|
|
2
|
-
import { MeshData } from './services/meshdata';
|
|
3
|
-
import { MeshFlow } from './services/meshflow';
|
|
4
1
|
import { HotMesh } from './services/hotmesh';
|
|
5
2
|
import { HotMeshConfig } from './types/hotmesh';
|
|
3
|
+
import { MeshCall } from './services/meshcall';
|
|
4
|
+
import { MeshFlow } from './services/meshflow';
|
|
5
|
+
import { MeshData } from './services/meshdata';
|
|
6
|
+
import { MeshOS } from './services/meshos';
|
|
6
7
|
|
|
7
|
-
export { HotMesh, MeshCall, MeshData, MeshFlow,
|
|
8
|
+
export { HotMesh, HotMeshConfig, MeshCall, MeshData, MeshFlow, MeshOS };
|
|
8
9
|
|
|
9
10
|
export * as Types from './types';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hotmeshio/hotmesh",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "Unbreakable Workflows",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"test:cycle": "NODE_ENV=test jest ./tests/functional/cycle/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
29
29
|
"test:meshflow": "NODE_ENV=test jest ./tests/meshflow/*/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
30
30
|
"test:meshflow:basic": "NODE_ENV=test jest ./tests/meshflow/basic/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
31
|
-
"test:meshflow:collision": "NODE_ENV=test jest ./tests/meshflow/collision/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
31
|
+
"test:meshflow:collision": "NODE_ENV=test HMSH_LOGLEVEL=debug jest ./tests/meshflow/collision/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
32
32
|
"test:meshflow:fatal": "NODE_ENV=test jest ./tests/meshflow/fatal/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
33
33
|
"test:meshflow:goodbye": "NODE_ENV=test jest ./tests/meshflow/goodbye/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
34
34
|
"test:meshflow:hello": "HMSH_IS_CLUSTER=true NODE_ENV=test jest ./tests/meshflow/helloworld/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"test:sub:redis": "NODE_ENV=test jest ./tests/functional/sub/clients/redis.test.ts --detectOpenHandles --forceExit --verbose",
|
|
65
65
|
"test:trigger": "NODE_ENV=test jest ./tests/unit/services/activities/trigger.test.ts --detectOpenHandles --forceExit --verbose",
|
|
66
66
|
"test:meshdata": "NODE_ENV=test HMSH_IS_CLUSTER=true jest ./tests/meshdata/index.test.ts --forceExit --verbose --detectOpenHandles",
|
|
67
|
+
"test:meshos": "NODE_ENV=test HMSH_IS_CLUSTER=true jest ./tests/meshos/index.test.ts --forceExit --verbose --detectOpenHandles",
|
|
67
68
|
"test:meshcall": "NODE_ENV=test HMSH_LOGLEVEL=debug jest ./tests/meshcall/index.test.ts --forceExit --verbose --detectOpenHandles",
|
|
68
69
|
"test:unit": "NODE_ENV=test jest ./tests/unit/*/*/index.test.ts --detectOpenHandles --forceExit --verbose"
|
|
69
70
|
},
|
package/typedoc.json
CHANGED
package/types/index.ts
CHANGED
|
@@ -91,6 +91,21 @@ export {
|
|
|
91
91
|
JobStatus,
|
|
92
92
|
PartialJobState,
|
|
93
93
|
} from './job';
|
|
94
|
+
export {
|
|
95
|
+
DB,
|
|
96
|
+
DBConfig,
|
|
97
|
+
Profile,
|
|
98
|
+
Namespaces,
|
|
99
|
+
Entity,
|
|
100
|
+
EntityInstanceTypes,
|
|
101
|
+
SubClassInstance,
|
|
102
|
+
AllSubclassInstances,
|
|
103
|
+
SubclassType,
|
|
104
|
+
Namespace,
|
|
105
|
+
Instance,
|
|
106
|
+
Instances,
|
|
107
|
+
Profiles,
|
|
108
|
+
} from './manifest';
|
|
94
109
|
export { MappingStatements } from './map';
|
|
95
110
|
export {
|
|
96
111
|
Pipe,
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { MeshOS } from '../services/meshos';
|
|
2
|
+
|
|
3
|
+
import * as Types from './index';
|
|
4
|
+
|
|
5
|
+
export type DBConfig = {
|
|
6
|
+
REDIS_DATABASE: number;
|
|
7
|
+
REDIS_HOST: string | undefined;
|
|
8
|
+
REDIS_PORT: number;
|
|
9
|
+
REDIS_USERNAME: string;
|
|
10
|
+
REDIS_PASSWORD: string;
|
|
11
|
+
REDIS_USE_TLS: boolean;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type DB = {
|
|
15
|
+
name: string;
|
|
16
|
+
label: string;
|
|
17
|
+
search: boolean;
|
|
18
|
+
config: DBConfig;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type SubClassInstance<T extends typeof MeshOS> = T extends abstract new (
|
|
22
|
+
...args: any
|
|
23
|
+
) => infer R
|
|
24
|
+
? R
|
|
25
|
+
: never;
|
|
26
|
+
export type AllSubclassInstances = SubClassInstance<
|
|
27
|
+
(typeof MeshOS)['classes'][keyof (typeof MeshOS)['classes']]
|
|
28
|
+
>;
|
|
29
|
+
|
|
30
|
+
//export type EntityClassTypes = typeof SubclassType;
|
|
31
|
+
export type EntityInstanceTypes = MeshOS;
|
|
32
|
+
|
|
33
|
+
export type SubclassType<T extends MeshOS = MeshOS> = new (...args: any[]) => T;
|
|
34
|
+
export type Entity = {
|
|
35
|
+
name: string;
|
|
36
|
+
label: string;
|
|
37
|
+
schema: Types.WorkflowSearchSchema;
|
|
38
|
+
class: SubclassType;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type Namespace = {
|
|
42
|
+
name: string;
|
|
43
|
+
type: string;
|
|
44
|
+
label: string;
|
|
45
|
+
entities: Entity[];
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type Namespaces = {
|
|
49
|
+
[key: string]: Namespace;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export type Instance = {
|
|
53
|
+
[key /*entity name*/ : string]: EntityInstanceTypes;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type Instances = {
|
|
57
|
+
[key /*namespace abbreviation*/ : string]: Instance;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export type Profile = {
|
|
61
|
+
db: DB;
|
|
62
|
+
namespaces: Namespaces;
|
|
63
|
+
instances?: Instances;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export type Profiles = {
|
|
67
|
+
[key: string]: Profile;
|
|
68
|
+
};
|
package/types/meshflow.ts
CHANGED