@hotmeshio/hotmesh 0.0.22 → 0.0.24
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 +66 -67
- package/build/index.d.ts +2 -1
- package/build/index.js +3 -1
- package/build/package.json +2 -1
- package/build/services/durable/connection.js +0 -39
- package/build/services/durable/factory.d.ts +6 -4
- package/build/services/durable/factory.js +12 -10
- package/build/services/durable/handle.d.ts +3 -0
- package/build/services/durable/handle.js +15 -5
- package/build/services/durable/index.d.ts +2 -45
- package/build/services/durable/index.js +2 -45
- package/build/services/durable/meshos.d.ts +108 -0
- package/build/services/durable/meshos.js +289 -0
- package/build/services/durable/search.d.ts +9 -0
- package/build/services/durable/search.js +34 -2
- package/build/services/durable/worker.d.ts +2 -10
- package/build/services/durable/worker.js +10 -39
- package/build/services/durable/workflow.d.ts +12 -1
- package/build/services/durable/workflow.js +32 -16
- package/build/services/engine/index.d.ts +2 -0
- package/build/services/engine/index.js +3 -0
- package/build/services/hotmesh/index.d.ts +3 -1
- package/build/services/hotmesh/index.js +5 -2
- package/build/services/signaler/stream.js +1 -2
- package/build/services/store/clients/ioredis.js +2 -2
- package/build/services/store/clients/redis.js +1 -1
- package/build/services/store/index.d.ts +5 -0
- package/build/services/store/index.js +14 -0
- package/build/types/durable.d.ts +34 -4
- package/build/types/index.d.ts +1 -1
- package/index.ts +2 -1
- package/package.json +2 -1
- package/services/durable/connection.ts +0 -40
- package/services/durable/factory.ts +12 -10
- package/services/durable/handle.ts +18 -5
- package/services/durable/index.ts +2 -46
- package/services/durable/meshos.ts +344 -0
- package/services/durable/search.ts +35 -2
- package/services/durable/worker.ts +11 -42
- package/services/durable/workflow.ts +34 -17
- package/services/engine/index.ts +4 -1
- package/services/hotmesh/index.ts +6 -2
- package/services/signaler/stream.ts +1 -2
- package/services/store/clients/ioredis.ts +2 -3
- package/services/store/clients/redis.ts +1 -1
- package/services/store/index.ts +15 -0
- package/types/durable.ts +40 -4
- package/types/index.ts +6 -1
- package/build/services/durable/native.d.ts +0 -4
- package/build/services/durable/native.js +0 -46
- package/services/durable/native.ts +0 -45
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
StatsResponse } from '../../types/stats';
|
|
22
22
|
import { ConnectorService } from '../connector';
|
|
23
23
|
import { StreamCode, StreamData, StreamDataResponse, StreamStatus } from '../../types/stream';
|
|
24
|
+
import { StringAnyType } from '../../types/serializer';
|
|
24
25
|
|
|
25
26
|
class HotMeshService {
|
|
26
27
|
namespace: string;
|
|
@@ -59,7 +60,7 @@ class HotMeshService {
|
|
|
59
60
|
instance.logger = new LoggerService(config.appId, instance.guid, config.name || '', config.logLevel);
|
|
60
61
|
await instance.initEngine(config, instance.logger);
|
|
61
62
|
await instance.initQuorum(config, instance.engine, instance.logger);
|
|
62
|
-
await instance.
|
|
63
|
+
await instance.doWork(config, instance.logger);
|
|
63
64
|
return instance;
|
|
64
65
|
}
|
|
65
66
|
|
|
@@ -97,7 +98,7 @@ class HotMeshService {
|
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
|
|
100
|
-
async
|
|
101
|
+
async doWork(config: HotMeshConfig, logger: ILogger) {
|
|
101
102
|
this.workers = await WorkerService.init(
|
|
102
103
|
this.namespace,
|
|
103
104
|
this.appId,
|
|
@@ -152,6 +153,9 @@ class HotMeshService {
|
|
|
152
153
|
async getState(topic: string, jobId: string): Promise<JobOutput> {
|
|
153
154
|
return this.engine?.getState(topic, jobId);
|
|
154
155
|
}
|
|
156
|
+
async getQueryState(jobId: string, fields: string[]): Promise<StringAnyType> {
|
|
157
|
+
return await this.engine?.getQueryState(jobId, fields);
|
|
158
|
+
}
|
|
155
159
|
async getIds(topic: string, query: JobStatsInput, queryFacets = []): Promise<IdsResponse> {
|
|
156
160
|
return await this.engine?.getIds(topic, query, queryFacets);
|
|
157
161
|
}
|
|
@@ -61,7 +61,7 @@ class StreamSignaler {
|
|
|
61
61
|
try {
|
|
62
62
|
await this.store.xgroup('CREATE', stream, group, '$', 'MKSTREAM');
|
|
63
63
|
} catch (err) {
|
|
64
|
-
this.logger.
|
|
64
|
+
this.logger.debug('consumer-group-exists', { stream, group });
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -150,7 +150,6 @@ class StreamSignaler {
|
|
|
150
150
|
try {
|
|
151
151
|
output = await callback(input);
|
|
152
152
|
} catch (error) {
|
|
153
|
-
console.error(error);
|
|
154
153
|
this.logger.error(`stream-call-function-error`, { error });
|
|
155
154
|
output = this.structureUnhandledError(input, error);
|
|
156
155
|
}
|
|
@@ -5,7 +5,6 @@ import { Cache } from '../cache';
|
|
|
5
5
|
import { StoreService } from '../index';
|
|
6
6
|
import { RedisClientType, RedisMultiType } from '../../../types/ioredisclient';
|
|
7
7
|
import { ReclaimedMessageType } from '../../../types/stream';
|
|
8
|
-
import { type } from 'os';
|
|
9
8
|
|
|
10
9
|
class IORedisStoreService extends StoreService<RedisClientType, RedisMultiType> {
|
|
11
10
|
redisClient: RedisClientType;
|
|
@@ -60,14 +59,14 @@ class IORedisStoreService extends StoreService<RedisClientType, RedisMultiType>
|
|
|
60
59
|
try {
|
|
61
60
|
return (await this.redisClient.xgroup(command, key, groupName, id, mkStream)) === 'OK';
|
|
62
61
|
} catch (err) {
|
|
63
|
-
this.logger.
|
|
62
|
+
this.logger.debug(`Consumer group not created with MKSTREAM for key: ${key} and group: ${groupName}`);
|
|
64
63
|
throw err;
|
|
65
64
|
}
|
|
66
65
|
} else {
|
|
67
66
|
try {
|
|
68
67
|
return (await this.redisClient.xgroup(command, key, groupName, id)) === 'OK';
|
|
69
68
|
} catch (err) {
|
|
70
|
-
this.logger.
|
|
69
|
+
this.logger.debug(`Consumer group not created for key: ${key} and group: ${groupName}`);
|
|
71
70
|
throw err;
|
|
72
71
|
}
|
|
73
72
|
}
|
|
@@ -86,7 +86,7 @@ class RedisStoreService extends StoreService<RedisClientType, RedisMultiType> {
|
|
|
86
86
|
return (await this.redisClient.sendCommand(['XGROUP', 'CREATE', key, groupName, id, ...args])) === 1;
|
|
87
87
|
} catch (error) {
|
|
88
88
|
const streamType = mkStream === 'MKSTREAM' ? 'with MKSTREAM' : 'without MKSTREAM';
|
|
89
|
-
this.logger.
|
|
89
|
+
this.logger.debug(`x-group-error ${streamType} for key: ${key} and group: ${groupName}`, { error });
|
|
90
90
|
throw error;
|
|
91
91
|
}
|
|
92
92
|
}
|
package/services/store/index.ts
CHANGED
|
@@ -476,6 +476,21 @@ abstract class StoreService<T, U extends AbstractRedisClient> {
|
|
|
476
476
|
return jobId;
|
|
477
477
|
}
|
|
478
478
|
|
|
479
|
+
/**
|
|
480
|
+
* returns custom search fields and values. The fields param
|
|
481
|
+
* should not prefix items with an underscore.
|
|
482
|
+
*/
|
|
483
|
+
async getQueryState(jobId: string, fields: string[]): Promise<StringAnyType> {
|
|
484
|
+
const key = this.mintKey(KeyType.JOB_STATE, { appId: this.appId, jobId });
|
|
485
|
+
const _fields = fields.map(field => `_${field}`);
|
|
486
|
+
const jobDataArray = await this.redisClient[this.commands.hmget](key, _fields);
|
|
487
|
+
const jobData: StringAnyType = {};
|
|
488
|
+
fields.forEach((field, index) => {
|
|
489
|
+
jobData[field] = jobDataArray[index];
|
|
490
|
+
});
|
|
491
|
+
return jobData;
|
|
492
|
+
}
|
|
493
|
+
|
|
479
494
|
async getState(jobId: string, consumes: Consumes, dIds: StringStringType): Promise<[StringAnyType, number] | undefined> {
|
|
480
495
|
//get abbreviated field list (the symbols for the paths)
|
|
481
496
|
const key = this.mintKey(KeyType.JOB_STATE, { appId: this.appId, jobId });
|
package/types/durable.ts
CHANGED
|
@@ -10,7 +10,7 @@ type WorkflowConfig = {
|
|
|
10
10
|
type WorkflowSearchOptions = {
|
|
11
11
|
index?: string; //FT index name (myapp:myindex)
|
|
12
12
|
prefix?: string[]; //FT prefixes (['myapp:myindex:prefix1', 'myapp:myindex:prefix2'])
|
|
13
|
-
schema?: Record<string, {type: 'TEXT' | 'NUMERIC' | 'TAG', sortable
|
|
13
|
+
schema?: Record<string, {type: 'TEXT' | 'NUMERIC' | 'TAG', sortable?: boolean}>;
|
|
14
14
|
data?: Record<string, string>;
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -57,12 +57,27 @@ type WorkflowDataType = {
|
|
|
57
57
|
workflowTopic: string;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
type MeshOSClassConfig = {
|
|
61
|
+
namespace: string;
|
|
62
|
+
taskQueue: string;
|
|
63
|
+
redisOptions: RedisOptions;
|
|
64
|
+
redisClass: RedisClass;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
type MeshOSConfig = {
|
|
68
|
+
taskQueue?: string;
|
|
69
|
+
index?: {
|
|
70
|
+
index: string;
|
|
71
|
+
prefix: string[];
|
|
72
|
+
schema: Record<string, {type: 'TEXT' | 'NUMERIC' | 'TAG', sortable: boolean}>;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
60
76
|
type ConnectionConfig = {
|
|
61
77
|
class: RedisClass;
|
|
62
78
|
options: RedisOptions;
|
|
63
79
|
}
|
|
64
80
|
type Connection = ConnectionConfig;
|
|
65
|
-
type NativeConnection = ConnectionConfig;
|
|
66
81
|
|
|
67
82
|
type ClientConfig = {
|
|
68
83
|
connection: Connection;
|
|
@@ -76,11 +91,28 @@ type WorkerConfig = {
|
|
|
76
91
|
connection: Connection;
|
|
77
92
|
namespace?: string; //`appid` in the YAML (e.g, 'default')
|
|
78
93
|
taskQueue: string; //`subscribes` in the YAML (e.g, 'hello-world')
|
|
79
|
-
workflow: Function
|
|
94
|
+
workflow: Function | Record<string | symbol, Function>; //target function to run
|
|
80
95
|
options?: WorkerOptions;
|
|
81
96
|
search?: WorkflowSearchOptions;
|
|
82
97
|
}
|
|
83
98
|
|
|
99
|
+
type FindOptions = {
|
|
100
|
+
workflowName?: string; //also the function name
|
|
101
|
+
taskQueue?: string;
|
|
102
|
+
namespace?: string;
|
|
103
|
+
index?: string; //the FT search index name
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
type MeshOSOptions = {
|
|
107
|
+
name: string;
|
|
108
|
+
options: WorkerOptions;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
type MeshOSActivityOptions = {
|
|
112
|
+
name: string;
|
|
113
|
+
options: ActivityConfig;
|
|
114
|
+
}
|
|
115
|
+
|
|
84
116
|
type WorkerOptions = {
|
|
85
117
|
logLevel?: string; //debug, info, warn, error
|
|
86
118
|
maxSystemRetries?: number; //1-3 (10ms, 100ms, 1_000ms)
|
|
@@ -115,11 +147,15 @@ export {
|
|
|
115
147
|
ContextType,
|
|
116
148
|
ConnectionConfig,
|
|
117
149
|
Connection,
|
|
118
|
-
NativeConnection,
|
|
119
150
|
ProxyType,
|
|
120
151
|
Registry,
|
|
121
152
|
SignalOptions,
|
|
153
|
+
FindOptions,
|
|
122
154
|
HookOptions,
|
|
155
|
+
MeshOSActivityOptions,
|
|
156
|
+
MeshOSClassConfig,
|
|
157
|
+
MeshOSConfig,
|
|
158
|
+
MeshOSOptions,
|
|
123
159
|
WorkerConfig,
|
|
124
160
|
WorkflowConfig,
|
|
125
161
|
WorkerOptions,
|
package/types/index.ts
CHANGED
|
@@ -34,10 +34,15 @@ export {
|
|
|
34
34
|
ContextType,
|
|
35
35
|
ConnectionConfig,
|
|
36
36
|
Connection,
|
|
37
|
-
NativeConnection,
|
|
38
37
|
ProxyType,
|
|
39
38
|
Registry,
|
|
39
|
+
SignalOptions,
|
|
40
|
+
FindOptions,
|
|
40
41
|
HookOptions,
|
|
42
|
+
MeshOSActivityOptions,
|
|
43
|
+
MeshOSClassConfig,
|
|
44
|
+
MeshOSConfig,
|
|
45
|
+
MeshOSOptions,
|
|
41
46
|
WorkflowConfig,
|
|
42
47
|
WorkerConfig,
|
|
43
48
|
WorkerOptions,
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NativeConnectionService = void 0;
|
|
4
|
-
/*
|
|
5
|
-
|
|
6
|
-
Here is an example of how the methods in this file are used:
|
|
7
|
-
|
|
8
|
-
./worker.ts
|
|
9
|
-
|
|
10
|
-
import { Durable: { NativeConnection, Worker } } from '@hotmeshio/hotmesh';
|
|
11
|
-
import Redis from 'ioredis'; //OR `import * as Redis from 'redis';`
|
|
12
|
-
|
|
13
|
-
import * as workflows from './workflows';
|
|
14
|
-
|
|
15
|
-
async function run() {
|
|
16
|
-
const connection = await NativeConnection.connect({
|
|
17
|
-
class: Redis,
|
|
18
|
-
options: {
|
|
19
|
-
host: 'localhost',
|
|
20
|
-
port: 6379,
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
const worker = await Worker.create({
|
|
24
|
-
connection,
|
|
25
|
-
taskQueue: 'hello-world',
|
|
26
|
-
workflow: workflows.example,
|
|
27
|
-
activities,
|
|
28
|
-
});
|
|
29
|
-
await worker.run();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
run().catch((err) => {
|
|
33
|
-
console.error(err);
|
|
34
|
-
process.exit(1);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
*/
|
|
38
|
-
class NativeConnectionService {
|
|
39
|
-
static async connect(config) {
|
|
40
|
-
return {
|
|
41
|
-
class: config.class,
|
|
42
|
-
options: { ...config.options },
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
exports.NativeConnectionService = NativeConnectionService;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Connection, ConnectionConfig } from "../../types/durable";
|
|
2
|
-
|
|
3
|
-
/*
|
|
4
|
-
|
|
5
|
-
Here is an example of how the methods in this file are used:
|
|
6
|
-
|
|
7
|
-
./worker.ts
|
|
8
|
-
|
|
9
|
-
import { Durable: { NativeConnection, Worker } } from '@hotmeshio/hotmesh';
|
|
10
|
-
import Redis from 'ioredis'; //OR `import * as Redis from 'redis';`
|
|
11
|
-
|
|
12
|
-
import * as workflows from './workflows';
|
|
13
|
-
|
|
14
|
-
async function run() {
|
|
15
|
-
const connection = await NativeConnection.connect({
|
|
16
|
-
class: Redis,
|
|
17
|
-
options: {
|
|
18
|
-
host: 'localhost',
|
|
19
|
-
port: 6379,
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
const worker = await Worker.create({
|
|
23
|
-
connection,
|
|
24
|
-
taskQueue: 'hello-world',
|
|
25
|
-
workflow: workflows.example,
|
|
26
|
-
activities,
|
|
27
|
-
});
|
|
28
|
-
await worker.run();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
run().catch((err) => {
|
|
32
|
-
console.error(err);
|
|
33
|
-
process.exit(1);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
export class NativeConnectionService {
|
|
39
|
-
static async connect(config: ConnectionConfig): Promise<Connection> {
|
|
40
|
-
return {
|
|
41
|
-
class: config.class,
|
|
42
|
-
options: { ...config.options },
|
|
43
|
-
} as Connection;
|
|
44
|
-
}
|
|
45
|
-
}
|