@hotmeshio/hotmesh 0.0.56 → 0.0.58
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 +10 -10
- package/build/modules/enums.js +10 -1
- package/build/modules/key.d.ts +38 -0
- package/build/modules/key.js +46 -4
- package/build/modules/utils.d.ts +9 -0
- package/build/modules/utils.js +19 -1
- package/build/package.json +1 -1
- package/build/services/activities/activity.d.ts +28 -0
- package/build/services/activities/activity.js +46 -1
- package/build/services/activities/await.js +4 -0
- package/build/services/activities/cycle.d.ts +7 -0
- package/build/services/activities/cycle.js +16 -1
- package/build/services/activities/hook.d.ts +6 -0
- package/build/services/activities/hook.js +12 -2
- package/build/services/activities/interrupt.js +8 -0
- package/build/services/activities/signal.d.ts +6 -0
- package/build/services/activities/signal.js +15 -0
- package/build/services/activities/trigger.d.ts +4 -0
- package/build/services/activities/trigger.js +7 -1
- package/build/services/activities/worker.js +4 -0
- package/build/services/collator/index.d.ts +70 -0
- package/build/services/collator/index.js +91 -1
- package/build/services/compiler/deployer.js +38 -6
- package/build/services/compiler/index.d.ts +15 -0
- package/build/services/compiler/index.js +20 -0
- package/build/services/compiler/validator.d.ts +3 -0
- package/build/services/compiler/validator.js +25 -0
- package/build/services/connector/clients/ioredis.js +2 -0
- package/build/services/connector/clients/redis.js +2 -0
- package/build/services/connector/index.js +2 -0
- package/build/services/durable/client.d.ts +20 -0
- package/build/services/durable/client.js +25 -0
- package/build/services/durable/exporter.d.ts +22 -0
- package/build/services/durable/exporter.js +30 -1
- package/build/services/durable/handle.d.ts +36 -0
- package/build/services/durable/handle.js +46 -0
- package/build/services/durable/index.d.ts +4 -0
- package/build/services/durable/index.js +4 -0
- package/build/services/durable/schemas/factory.d.ts +29 -0
- package/build/services/durable/schemas/factory.js +29 -0
- package/build/services/durable/search.d.ts +97 -0
- package/build/services/durable/search.js +108 -10
- package/build/services/durable/worker.js +35 -6
- package/build/services/durable/workflow.d.ts +118 -0
- package/build/services/durable/workflow.js +153 -6
- package/build/services/engine/index.d.ts +5 -0
- package/build/services/engine/index.js +43 -1
- package/build/services/exporter/index.d.ts +27 -0
- package/build/services/exporter/index.js +33 -0
- package/build/services/hotmesh/index.js +8 -0
- package/build/services/logger/index.js +2 -0
- package/build/services/mapper/index.d.ts +14 -0
- package/build/services/mapper/index.js +14 -0
- package/build/services/pipe/functions/date.d.ts +7 -0
- package/build/services/pipe/functions/date.js +7 -0
- package/build/services/pipe/functions/math.js +2 -0
- package/build/services/pipe/index.d.ts +15 -0
- package/build/services/pipe/index.js +23 -2
- package/build/services/quorum/index.d.ts +7 -0
- package/build/services/quorum/index.js +21 -0
- package/build/services/reporter/index.d.ts +5 -0
- package/build/services/reporter/index.js +9 -0
- package/build/services/router/index.d.ts +9 -0
- package/build/services/router/index.js +30 -2
- package/build/services/serializer/index.js +23 -6
- package/build/services/store/cache.d.ts +19 -0
- package/build/services/store/cache.js +19 -0
- package/build/services/store/clients/ioredis.js +1 -0
- package/build/services/store/index.d.ts +55 -0
- package/build/services/store/index.js +81 -5
- package/build/services/stream/clients/ioredis.js +4 -1
- package/build/services/task/index.d.ts +9 -0
- package/build/services/task/index.js +31 -0
- package/build/services/telemetry/index.d.ts +7 -0
- package/build/services/telemetry/index.js +13 -1
- package/build/services/worker/index.d.ts +4 -0
- package/build/services/worker/index.js +6 -2
- package/build/types/activity.d.ts +81 -0
- package/build/types/durable.d.ts +256 -0
- package/build/types/exporter.d.ts +13 -0
- package/build/types/hotmesh.d.ts +10 -1
- package/build/types/hotmesh.js +3 -0
- package/build/types/index.js +1 -1
- package/build/types/job.d.ts +85 -0
- package/build/types/pipe.d.ts +65 -0
- package/build/types/quorum.d.ts +14 -0
- package/build/types/redis.d.ts +6 -0
- package/build/types/stream.d.ts +58 -0
- package/build/types/stream.js +4 -0
- package/package.json +1 -1
- package/types/durable.ts +10 -1
|
@@ -10,11 +10,47 @@ export declare class WorkflowHandleService {
|
|
|
10
10
|
workflowId: string;
|
|
11
11
|
constructor(hotMesh: HotMesh, workflowTopic: string, workflowId: string);
|
|
12
12
|
export(options?: ExportOptions): Promise<DurableJobExport>;
|
|
13
|
+
/**
|
|
14
|
+
* Sends a signal to the workflow. This is a way to send
|
|
15
|
+
* a message to a workflow that is paused due to having
|
|
16
|
+
* executed `Durable.workflow.waitFor`. The workflow
|
|
17
|
+
* will awaken if no other signals are pending.
|
|
18
|
+
*/
|
|
13
19
|
signal(signalId: string, data: Record<any, any>): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Returns the job state of the workflow. If the workflow has completed
|
|
22
|
+
* this is also the job output. If the workflow is still running, this
|
|
23
|
+
* is the current state of the job, but it may change depending upon
|
|
24
|
+
* the activities that remain.
|
|
25
|
+
*/
|
|
14
26
|
state(metadata?: boolean): Promise<Record<string, any>>;
|
|
27
|
+
/**
|
|
28
|
+
* Returns the current search state of the workflow. This is
|
|
29
|
+
* different than the job state or individual activity state.
|
|
30
|
+
* Search state represents name/value pairs that were added
|
|
31
|
+
* to the workflow. As the workflow is stored in a Redis hash,
|
|
32
|
+
* this is a way to store additional data that is indexed
|
|
33
|
+
* and searchable using the RediSearch module.
|
|
34
|
+
*/
|
|
15
35
|
queryState(fields: string[]): Promise<Record<string, any>>;
|
|
36
|
+
/**
|
|
37
|
+
* Returns the current status of the workflow. This is a semaphore
|
|
38
|
+
* value that represents the current state of the workflow, where
|
|
39
|
+
* 0 is complete and a negative value represents that the flow was
|
|
40
|
+
* interrupted.
|
|
41
|
+
*/
|
|
16
42
|
status(): Promise<number>;
|
|
43
|
+
/**
|
|
44
|
+
* Interrupts a running workflow. Standard Job Completion tasks will
|
|
45
|
+
* run. Subscribers will be notified and the job hash will be expired.
|
|
46
|
+
*/
|
|
17
47
|
interrupt(options?: JobInterruptOptions): Promise<string>;
|
|
48
|
+
/**
|
|
49
|
+
* Waits for the workflow to complete and returns the result. If
|
|
50
|
+
* the workflow response includes an error, this method will rethrow
|
|
51
|
+
* the error, including the stack trace if available.
|
|
52
|
+
* Wrap calls in a try/catch as necessary to avoid unhandled exceptions.
|
|
53
|
+
*/
|
|
18
54
|
result<T>(config?: {
|
|
19
55
|
state?: boolean;
|
|
20
56
|
throwOnError?: boolean;
|
|
@@ -12,9 +12,21 @@ class WorkflowHandleService {
|
|
|
12
12
|
async export(options) {
|
|
13
13
|
return this.exporter.export(this.workflowId, options);
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Sends a signal to the workflow. This is a way to send
|
|
17
|
+
* a message to a workflow that is paused due to having
|
|
18
|
+
* executed `Durable.workflow.waitFor`. The workflow
|
|
19
|
+
* will awaken if no other signals are pending.
|
|
20
|
+
*/
|
|
15
21
|
async signal(signalId, data) {
|
|
16
22
|
await this.hotMesh.hook(`${this.hotMesh.appId}.wfs.signal`, { id: signalId, data });
|
|
17
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Returns the job state of the workflow. If the workflow has completed
|
|
26
|
+
* this is also the job output. If the workflow is still running, this
|
|
27
|
+
* is the current state of the job, but it may change depending upon
|
|
28
|
+
* the activities that remain.
|
|
29
|
+
*/
|
|
18
30
|
async state(metadata = false) {
|
|
19
31
|
const state = await this.hotMesh.getState(`${this.hotMesh.appId}.execute`, this.workflowId);
|
|
20
32
|
if (!state.data && state.metadata.err) {
|
|
@@ -22,25 +34,56 @@ class WorkflowHandleService {
|
|
|
22
34
|
}
|
|
23
35
|
return metadata ? state : state.data;
|
|
24
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Returns the current search state of the workflow. This is
|
|
39
|
+
* different than the job state or individual activity state.
|
|
40
|
+
* Search state represents name/value pairs that were added
|
|
41
|
+
* to the workflow. As the workflow is stored in a Redis hash,
|
|
42
|
+
* this is a way to store additional data that is indexed
|
|
43
|
+
* and searchable using the RediSearch module.
|
|
44
|
+
*/
|
|
25
45
|
async queryState(fields) {
|
|
26
46
|
return await this.hotMesh.getQueryState(this.workflowId, fields);
|
|
27
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Returns the current status of the workflow. This is a semaphore
|
|
50
|
+
* value that represents the current state of the workflow, where
|
|
51
|
+
* 0 is complete and a negative value represents that the flow was
|
|
52
|
+
* interrupted.
|
|
53
|
+
*/
|
|
28
54
|
async status() {
|
|
29
55
|
return await this.hotMesh.getStatus(this.workflowId);
|
|
30
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Interrupts a running workflow. Standard Job Completion tasks will
|
|
59
|
+
* run. Subscribers will be notified and the job hash will be expired.
|
|
60
|
+
*/
|
|
31
61
|
async interrupt(options) {
|
|
32
62
|
return await this.hotMesh.interrupt(`${this.hotMesh.appId}.execute`, this.workflowId, options);
|
|
33
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Waits for the workflow to complete and returns the result. If
|
|
66
|
+
* the workflow response includes an error, this method will rethrow
|
|
67
|
+
* the error, including the stack trace if available.
|
|
68
|
+
* Wrap calls in a try/catch as necessary to avoid unhandled exceptions.
|
|
69
|
+
*/
|
|
34
70
|
async result(config) {
|
|
35
71
|
const topic = `${this.hotMesh.appId}.executed.${this.workflowId}`;
|
|
36
72
|
let isResolved = false;
|
|
37
73
|
return new Promise(async (resolve, reject) => {
|
|
74
|
+
/**
|
|
75
|
+
* rejects/resolves the promise based on the `throwOnError`
|
|
76
|
+
* default behavior is to throw if error
|
|
77
|
+
*/
|
|
38
78
|
const safeReject = (err) => {
|
|
39
79
|
if (config?.throwOnError === false) {
|
|
40
80
|
return resolve(err);
|
|
41
81
|
}
|
|
42
82
|
reject(err);
|
|
43
83
|
};
|
|
84
|
+
/**
|
|
85
|
+
* Common completion function that unsubscribes from the topic/returns
|
|
86
|
+
*/
|
|
44
87
|
const complete = async (response, err) => {
|
|
45
88
|
if (isResolved)
|
|
46
89
|
return;
|
|
@@ -63,6 +106,7 @@ class WorkflowHandleService {
|
|
|
63
106
|
}
|
|
64
107
|
resolve(response);
|
|
65
108
|
};
|
|
109
|
+
//more expensive; fetches the entire job, not just the `status`
|
|
66
110
|
if (config?.state) {
|
|
67
111
|
const state = await this.hotMesh.getState(`${this.hotMesh.appId}.execute`, this.workflowId);
|
|
68
112
|
if (state?.data?.done && !state.data?.$error) {
|
|
@@ -75,6 +119,7 @@ class WorkflowHandleService {
|
|
|
75
119
|
return complete(null, JSON.parse(state.metadata.err));
|
|
76
120
|
}
|
|
77
121
|
}
|
|
122
|
+
//subscribe to 'done' topic
|
|
78
123
|
this.hotMesh.sub(topic, async (_topic, state) => {
|
|
79
124
|
this.hotMesh.unsub(topic);
|
|
80
125
|
if (state.data.done && !state.data?.$error) {
|
|
@@ -88,6 +133,7 @@ class WorkflowHandleService {
|
|
|
88
133
|
return await complete(null, error);
|
|
89
134
|
}
|
|
90
135
|
});
|
|
136
|
+
//check state in case completed during wiring
|
|
91
137
|
const status = await this.hotMesh.getStatus(this.workflowId);
|
|
92
138
|
if (status <= 0) {
|
|
93
139
|
await complete();
|
|
@@ -10,6 +10,10 @@ export declare const Durable: {
|
|
|
10
10
|
Search: typeof Search;
|
|
11
11
|
Worker: typeof WorkerService;
|
|
12
12
|
workflow: typeof WorkflowService;
|
|
13
|
+
/**
|
|
14
|
+
* Shutdown everything. All connections, workers, and clients will be closed.
|
|
15
|
+
* Include in your signal handlers to ensure a clean shutdown.
|
|
16
|
+
*/
|
|
13
17
|
shutdown(): Promise<void>;
|
|
14
18
|
};
|
|
15
19
|
export type { ContextType };
|
|
@@ -13,6 +13,10 @@ exports.Durable = {
|
|
|
13
13
|
Search: search_1.Search,
|
|
14
14
|
Worker: worker_1.WorkerService,
|
|
15
15
|
workflow: workflow_1.WorkflowService,
|
|
16
|
+
/**
|
|
17
|
+
* Shutdown everything. All connections, workers, and clients will be closed.
|
|
18
|
+
* Include in your signal handlers to ensure a clean shutdown.
|
|
19
|
+
*/
|
|
16
20
|
async shutdown() {
|
|
17
21
|
await client_1.ClientService.shutdown();
|
|
18
22
|
await worker_1.WorkerService.shutdown();
|
|
@@ -1,4 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*********** HOTMESH 'DURABLE' MODULE APPLICATION GRAPH **********
|
|
3
|
+
*
|
|
4
|
+
* This HotMesh application spec uses 50 activities and 25 transitions
|
|
5
|
+
* to model and emulate the Temporal Application & Query servers using
|
|
6
|
+
* Redis as the backend.
|
|
7
|
+
*
|
|
8
|
+
* It's particularly useful for organizations with high-speed, high-volume
|
|
9
|
+
* use cases as it uses in-memory Redis Streams for transactional,
|
|
10
|
+
* workflow processing, while adhering to Temporal's developer-friendly syntax.
|
|
11
|
+
*
|
|
12
|
+
* This YAML file can also serve as a useful starting point for building
|
|
13
|
+
* Integration/BPM/Workflow servers in general (MuleSoft, etc) without the need
|
|
14
|
+
* for a physical application server.
|
|
15
|
+
*
|
|
16
|
+
* Possible use cases include:
|
|
17
|
+
* * Orchestration servers
|
|
18
|
+
* * Integration servers
|
|
19
|
+
* * BPMN engines
|
|
20
|
+
* * Reentrant process servers
|
|
21
|
+
* * Service Meshes
|
|
22
|
+
* * Master Data Management systems
|
|
23
|
+
*/
|
|
1
24
|
declare const APP_VERSION = "1";
|
|
2
25
|
declare const APP_ID = "durable";
|
|
26
|
+
/**
|
|
27
|
+
* returns a new durable workflow schema
|
|
28
|
+
* @param {string} app - app name (e.g., 'durable')
|
|
29
|
+
* @param {string} version - number as string (e.g., '1')
|
|
30
|
+
* @returns {string} HotMesh App YAML
|
|
31
|
+
*/
|
|
3
32
|
declare const getWorkflowYAML: (app: string, version: string) => string;
|
|
4
33
|
export { getWorkflowYAML, APP_VERSION, APP_ID, };
|
|
@@ -1,10 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
*********** HOTMESH 'DURABLE' MODULE APPLICATION GRAPH **********
|
|
4
|
+
*
|
|
5
|
+
* This HotMesh application spec uses 50 activities and 25 transitions
|
|
6
|
+
* to model and emulate the Temporal Application & Query servers using
|
|
7
|
+
* Redis as the backend.
|
|
8
|
+
*
|
|
9
|
+
* It's particularly useful for organizations with high-speed, high-volume
|
|
10
|
+
* use cases as it uses in-memory Redis Streams for transactional,
|
|
11
|
+
* workflow processing, while adhering to Temporal's developer-friendly syntax.
|
|
12
|
+
*
|
|
13
|
+
* This YAML file can also serve as a useful starting point for building
|
|
14
|
+
* Integration/BPM/Workflow servers in general (MuleSoft, etc) without the need
|
|
15
|
+
* for a physical application server.
|
|
16
|
+
*
|
|
17
|
+
* Possible use cases include:
|
|
18
|
+
* * Orchestration servers
|
|
19
|
+
* * Integration servers
|
|
20
|
+
* * BPMN engines
|
|
21
|
+
* * Reentrant process servers
|
|
22
|
+
* * Service Meshes
|
|
23
|
+
* * Master Data Management systems
|
|
24
|
+
*/
|
|
2
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
26
|
exports.APP_ID = exports.APP_VERSION = exports.getWorkflowYAML = void 0;
|
|
4
27
|
const APP_VERSION = '1';
|
|
5
28
|
exports.APP_VERSION = APP_VERSION;
|
|
6
29
|
const APP_ID = 'durable';
|
|
7
30
|
exports.APP_ID = APP_ID;
|
|
31
|
+
/**
|
|
32
|
+
* returns a new durable workflow schema
|
|
33
|
+
* @param {string} app - app name (e.g., 'durable')
|
|
34
|
+
* @param {string} version - number as string (e.g., '1')
|
|
35
|
+
* @returns {string} HotMesh App YAML
|
|
36
|
+
*/
|
|
8
37
|
const getWorkflowYAML = (app, version) => {
|
|
9
38
|
return `app:
|
|
10
39
|
id: ${app}
|
|
@@ -10,14 +10,111 @@ export declare class Search {
|
|
|
10
10
|
store: StoreService<RedisClient, RedisMulti> | null;
|
|
11
11
|
cachedFields: Record<string, string>;
|
|
12
12
|
constructor(workflowId: string, hotMeshClient: HotMesh, searchSessionId: string);
|
|
13
|
+
/**
|
|
14
|
+
* Prefixes the key with an underscore to keep separate from the
|
|
15
|
+
* activity and job history (and searchable via HKEYS)
|
|
16
|
+
* @param {string} key - the key to be sanitized. Wrap in quotes to avoid sanitization.
|
|
17
|
+
* @returns {string} - the sanitized key
|
|
18
|
+
* @private
|
|
19
|
+
*/
|
|
13
20
|
safeKey(key: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* For those deployments with a redis stack backend (with the FT module),
|
|
23
|
+
* this method will configure the search index for the workflow. For all
|
|
24
|
+
* others, this method will exit/fail gracefully and not index
|
|
25
|
+
* the fields in the HASH. All values are searchable via HKEYS/HSC/HGET
|
|
26
|
+
* @param {HotMesh} hotMeshClient - the hotmesh client
|
|
27
|
+
* @param {WorkflowSearchOptions} search - the search options
|
|
28
|
+
* @returns {Promise<void>}
|
|
29
|
+
* @example
|
|
30
|
+
* const search = {
|
|
31
|
+
* index: 'my_search_index',
|
|
32
|
+
* prefix: ['my_workflow_prefix'],
|
|
33
|
+
* schema: {
|
|
34
|
+
* field1: { type: 'TEXT', sortable: true },
|
|
35
|
+
* field2: { type: 'NUMERIC', sortable: true }
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
* await Search.configureSearchIndex(hotMeshClient, search);
|
|
39
|
+
*/
|
|
14
40
|
static configureSearchIndex(hotMeshClient: HotMesh, search?: WorkflowSearchOptions): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* For those deployments with a redis stack backend (with the FT module),
|
|
43
|
+
* this method will list all search indexes.
|
|
44
|
+
*
|
|
45
|
+
* @param {HotMesh} hotMeshClient - the hotmesh client
|
|
46
|
+
* @returns {Promise<string[]>} - the list of search indexes
|
|
47
|
+
* @example
|
|
48
|
+
* const searchIndexes = await Search.listSearchIndexes(hotMeshClient);
|
|
49
|
+
*/
|
|
15
50
|
static listSearchIndexes(hotMeshClient: HotMesh): Promise<string[]>;
|
|
51
|
+
/**
|
|
52
|
+
* increments the index to return a unique search session guid when
|
|
53
|
+
* calling any method that produces side effects (changes the value)
|
|
54
|
+
* @private
|
|
55
|
+
*/
|
|
16
56
|
getSearchSessionGuid(): string;
|
|
57
|
+
/**
|
|
58
|
+
* Sets the fields listed in args. Returns the
|
|
59
|
+
* count of new fields that were set (does not
|
|
60
|
+
* count fields that were updated)
|
|
61
|
+
* @param args
|
|
62
|
+
* @returns {number}
|
|
63
|
+
* @example
|
|
64
|
+
* const search = new Search();
|
|
65
|
+
* const count = await search.set('field1', 'value1', 'field2', 'value2');
|
|
66
|
+
*/
|
|
17
67
|
set(...args: string[]): Promise<number>;
|
|
68
|
+
/**
|
|
69
|
+
* Returns the value of the field in the HASH stored at key.
|
|
70
|
+
* @param key
|
|
71
|
+
* @returns {string}
|
|
72
|
+
* @example
|
|
73
|
+
* const search = new Search();
|
|
74
|
+
* const value = await search.get('field1');
|
|
75
|
+
*/
|
|
18
76
|
get(key: string): Promise<string>;
|
|
77
|
+
/**
|
|
78
|
+
* Returns the values of all specified fields in the HASH stored at key.
|
|
79
|
+
* @param args
|
|
80
|
+
* @returns
|
|
81
|
+
*/
|
|
19
82
|
mget(...args: string[]): Promise<string[]>;
|
|
83
|
+
/**
|
|
84
|
+
* Deletes the fields provided as args. Returns the
|
|
85
|
+
* count of fields that were deleted.
|
|
86
|
+
*
|
|
87
|
+
* @param args
|
|
88
|
+
* @returns {number}
|
|
89
|
+
* @example
|
|
90
|
+
* sont search = new Search();
|
|
91
|
+
* const count = await search.del('field1', 'field2', 'field3');
|
|
92
|
+
*/
|
|
20
93
|
del(...args: string[]): Promise<number | void>;
|
|
94
|
+
/**
|
|
95
|
+
* Increments the value of a float field by the given amount. Returns the
|
|
96
|
+
* new value of the field after the increment. Pass a negative
|
|
97
|
+
* number to decrement the value.
|
|
98
|
+
*
|
|
99
|
+
* @param key - the key to increment
|
|
100
|
+
* @param val - the value to increment by
|
|
101
|
+
* @returns {number} - the new value
|
|
102
|
+
* @example
|
|
103
|
+
* const search = new Search();
|
|
104
|
+
* const count = await search.incr('field1', 1.5);
|
|
105
|
+
*/
|
|
21
106
|
incr(key: string, val: number): Promise<number>;
|
|
107
|
+
/**
|
|
108
|
+
* Multiplies the value of a field by the given amount. Returns the
|
|
109
|
+
* new value of the field after the multiplication. NOTE:
|
|
110
|
+
* this is exponential multiplication.
|
|
111
|
+
*
|
|
112
|
+
* @param key - the key to multiply
|
|
113
|
+
* @param val - the value to multiply by
|
|
114
|
+
* @returns {number} - the new product of the multiplication
|
|
115
|
+
* @example
|
|
116
|
+
* const search = new Search();
|
|
117
|
+
* const product = await search.mult('field1', 1.5);
|
|
118
|
+
*/
|
|
22
119
|
mult(key: string, val: number): Promise<number>;
|
|
23
120
|
}
|
|
@@ -16,31 +16,56 @@ class Search {
|
|
|
16
16
|
this.hotMeshClient = hotMeshClient;
|
|
17
17
|
this.store = hotMeshClient.engine.store;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Prefixes the key with an underscore to keep separate from the
|
|
21
|
+
* activity and job history (and searchable via HKEYS)
|
|
22
|
+
* @param {string} key - the key to be sanitized. Wrap in quotes to avoid sanitization.
|
|
23
|
+
* @returns {string} - the sanitized key
|
|
24
|
+
* @private
|
|
25
|
+
*/
|
|
19
26
|
safeKey(key) {
|
|
20
27
|
if (key.startsWith('"')) {
|
|
21
28
|
return key.slice(1, -1);
|
|
22
29
|
}
|
|
23
30
|
return `_${key}`;
|
|
24
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* For those deployments with a redis stack backend (with the FT module),
|
|
34
|
+
* this method will configure the search index for the workflow. For all
|
|
35
|
+
* others, this method will exit/fail gracefully and not index
|
|
36
|
+
* the fields in the HASH. All values are searchable via HKEYS/HSC/HGET
|
|
37
|
+
* @param {HotMesh} hotMeshClient - the hotmesh client
|
|
38
|
+
* @param {WorkflowSearchOptions} search - the search options
|
|
39
|
+
* @returns {Promise<void>}
|
|
40
|
+
* @example
|
|
41
|
+
* const search = {
|
|
42
|
+
* index: 'my_search_index',
|
|
43
|
+
* prefix: ['my_workflow_prefix'],
|
|
44
|
+
* schema: {
|
|
45
|
+
* field1: { type: 'TEXT', sortable: true },
|
|
46
|
+
* field2: { type: 'NUMERIC', sortable: true }
|
|
47
|
+
* }
|
|
48
|
+
* }
|
|
49
|
+
* await Search.configureSearchIndex(hotMeshClient, search);
|
|
50
|
+
*/
|
|
25
51
|
static async configureSearchIndex(hotMeshClient, search) {
|
|
26
52
|
if (search?.schema) {
|
|
27
53
|
const store = hotMeshClient.engine.store;
|
|
28
54
|
const schema = [];
|
|
29
55
|
for (const [key, value] of Object.entries(search.schema)) {
|
|
30
56
|
if (value.indexed !== false) {
|
|
31
|
-
schema.push(`_${key}`);
|
|
32
|
-
schema.push(value.type);
|
|
33
|
-
if (value.sortable) {
|
|
34
|
-
schema.push('SORTABLE');
|
|
35
|
-
}
|
|
36
|
-
if (value.sortable) {
|
|
37
|
-
schema.push('SORTABLE');
|
|
38
|
-
}
|
|
57
|
+
schema.push(value.fieldName ? `${value.fieldName.toString()}` : `_${key}`);
|
|
58
|
+
schema.push(value.type ? value.type : 'TEXT');
|
|
39
59
|
if (value.noindex) {
|
|
40
60
|
schema.push('NOINDEX');
|
|
41
61
|
}
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
else {
|
|
63
|
+
if (value.nostem && value.type === 'TEXT') {
|
|
64
|
+
schema.push('NOSTEM');
|
|
65
|
+
}
|
|
66
|
+
if (value.sortable) {
|
|
67
|
+
schema.push('SORTABLE');
|
|
68
|
+
}
|
|
44
69
|
}
|
|
45
70
|
}
|
|
46
71
|
}
|
|
@@ -58,6 +83,15 @@ class Search {
|
|
|
58
83
|
}
|
|
59
84
|
}
|
|
60
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* For those deployments with a redis stack backend (with the FT module),
|
|
88
|
+
* this method will list all search indexes.
|
|
89
|
+
*
|
|
90
|
+
* @param {HotMesh} hotMeshClient - the hotmesh client
|
|
91
|
+
* @returns {Promise<string[]>} - the list of search indexes
|
|
92
|
+
* @example
|
|
93
|
+
* const searchIndexes = await Search.listSearchIndexes(hotMeshClient);
|
|
94
|
+
*/
|
|
61
95
|
static async listSearchIndexes(hotMeshClient) {
|
|
62
96
|
try {
|
|
63
97
|
const store = hotMeshClient.engine.store;
|
|
@@ -69,9 +103,25 @@ class Search {
|
|
|
69
103
|
return [];
|
|
70
104
|
}
|
|
71
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* increments the index to return a unique search session guid when
|
|
108
|
+
* calling any method that produces side effects (changes the value)
|
|
109
|
+
* @private
|
|
110
|
+
*/
|
|
72
111
|
getSearchSessionGuid() {
|
|
112
|
+
//return the search session as it would exist in the search session index
|
|
73
113
|
return `${this.searchSessionId}-${this.searchSessionIndex++}-`;
|
|
74
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Sets the fields listed in args. Returns the
|
|
117
|
+
* count of new fields that were set (does not
|
|
118
|
+
* count fields that were updated)
|
|
119
|
+
* @param args
|
|
120
|
+
* @returns {number}
|
|
121
|
+
* @example
|
|
122
|
+
* const search = new Search();
|
|
123
|
+
* const count = await search.set('field1', 'value1', 'field2', 'value2');
|
|
124
|
+
*/
|
|
75
125
|
async set(...args) {
|
|
76
126
|
const ssGuid = this.getSearchSessionGuid();
|
|
77
127
|
const store = storage_1.asyncLocalStorage.getStore();
|
|
@@ -88,9 +138,18 @@ class Search {
|
|
|
88
138
|
return Number(replay[ssGuid]);
|
|
89
139
|
}
|
|
90
140
|
const fieldCount = await this.store.exec('HSET', this.jobId, ...safeArgs);
|
|
141
|
+
//no need to wait; set this interim value in the replay
|
|
91
142
|
this.store.exec('HSET', this.jobId, ssGuid, fieldCount.toString());
|
|
92
143
|
return Number(fieldCount);
|
|
93
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Returns the value of the field in the HASH stored at key.
|
|
147
|
+
* @param key
|
|
148
|
+
* @returns {string}
|
|
149
|
+
* @example
|
|
150
|
+
* const search = new Search();
|
|
151
|
+
* const value = await search.get('field1');
|
|
152
|
+
*/
|
|
94
153
|
async get(key) {
|
|
95
154
|
try {
|
|
96
155
|
if (key in this.cachedFields) {
|
|
@@ -105,6 +164,11 @@ class Search {
|
|
|
105
164
|
return '';
|
|
106
165
|
}
|
|
107
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* Returns the values of all specified fields in the HASH stored at key.
|
|
169
|
+
* @param args
|
|
170
|
+
* @returns
|
|
171
|
+
*/
|
|
108
172
|
async mget(...args) {
|
|
109
173
|
let isCached = true;
|
|
110
174
|
const values = [];
|
|
@@ -135,6 +199,16 @@ class Search {
|
|
|
135
199
|
return [];
|
|
136
200
|
}
|
|
137
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* Deletes the fields provided as args. Returns the
|
|
204
|
+
* count of fields that were deleted.
|
|
205
|
+
*
|
|
206
|
+
* @param args
|
|
207
|
+
* @returns {number}
|
|
208
|
+
* @example
|
|
209
|
+
* sont search = new Search();
|
|
210
|
+
* const count = await search.del('field1', 'field2', 'field3');
|
|
211
|
+
*/
|
|
138
212
|
async del(...args) {
|
|
139
213
|
const ssGuid = this.getSearchSessionGuid();
|
|
140
214
|
const store = storage_1.asyncLocalStorage.getStore();
|
|
@@ -153,6 +227,18 @@ class Search {
|
|
|
153
227
|
this.store.exec('HSET', this.jobId, ssGuid, formattedResponse.toString());
|
|
154
228
|
return formattedResponse;
|
|
155
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* Increments the value of a float field by the given amount. Returns the
|
|
232
|
+
* new value of the field after the increment. Pass a negative
|
|
233
|
+
* number to decrement the value.
|
|
234
|
+
*
|
|
235
|
+
* @param key - the key to increment
|
|
236
|
+
* @param val - the value to increment by
|
|
237
|
+
* @returns {number} - the new value
|
|
238
|
+
* @example
|
|
239
|
+
* const search = new Search();
|
|
240
|
+
* const count = await search.incr('field1', 1.5);
|
|
241
|
+
*/
|
|
156
242
|
async incr(key, val) {
|
|
157
243
|
delete this.cachedFields[key];
|
|
158
244
|
const ssGuid = this.getSearchSessionGuid();
|
|
@@ -165,6 +251,18 @@ class Search {
|
|
|
165
251
|
this.store.exec('HSET', this.jobId, ssGuid, num.toString());
|
|
166
252
|
return Number(num);
|
|
167
253
|
}
|
|
254
|
+
/**
|
|
255
|
+
* Multiplies the value of a field by the given amount. Returns the
|
|
256
|
+
* new value of the field after the multiplication. NOTE:
|
|
257
|
+
* this is exponential multiplication.
|
|
258
|
+
*
|
|
259
|
+
* @param key - the key to multiply
|
|
260
|
+
* @param val - the value to multiply by
|
|
261
|
+
* @returns {number} - the new product of the multiplication
|
|
262
|
+
* @example
|
|
263
|
+
* const search = new Search();
|
|
264
|
+
* const product = await search.mult('field1', 1.5);
|
|
265
|
+
*/
|
|
168
266
|
async mult(key, val) {
|
|
169
267
|
delete this.cachedFields[key];
|
|
170
268
|
const ssGuid = this.getSearchSessionGuid();
|