@hotmeshio/hotmesh 0.0.26 → 0.0.27
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 +4 -2
- package/build/package.json +1 -1
- package/build/services/durable/meshos.js +4 -4
- package/build/services/durable/search.d.ts +3 -2
- package/build/services/durable/search.js +28 -5
- package/build/types/durable.d.ts +1 -1
- package/package.json +1 -1
- package/services/durable/meshos.ts +4 -4
- package/services/durable/search.ts +28 -5
- package/types/durable.ts +1 -1
package/README.md
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
|
|
4
4
|
Elevate Redis from an in-memory data cache, and turn your unpredictable functions into unbreakable workflows.
|
|
5
5
|
|
|
6
|
-
**HotMesh** is a wrapper for Redis that exposes
|
|
6
|
+
**HotMesh** is a wrapper for Redis that exposes concepts like ‘activities’, ‘workflows’, and 'jobs'. Behind the scenes, it uses *Redis Data* (Hash, ZSet, List); *Redis Streams* (XReadGroup, XAdd, XLen, etc); and *Redis Publish/Subscribe*.
|
|
7
7
|
|
|
8
|
-
It's still Redis in the background, but
|
|
8
|
+
It's still Redis in the background, but your functions are run as *reentrant processes* and are executed in a distributed environment, with all the benefits of a distributed system, including fault tolerance, scalability, and high availability.
|
|
9
|
+
|
|
10
|
+
Write functions in your own preferred style, and let Redis govern their execution at its unmatched scale and performance.
|
|
9
11
|
|
|
10
12
|
## Install
|
|
11
13
|
[](https://badge.fury.io/js/%40hotmeshio%2Fhotmesh)
|
package/build/package.json
CHANGED
|
@@ -206,16 +206,16 @@ class MeshOSService {
|
|
|
206
206
|
return `${prefixedFieldName}:"${value}"`;
|
|
207
207
|
case 'NUMERIC':
|
|
208
208
|
let range = '';
|
|
209
|
-
if (is.startsWith('=')) {
|
|
209
|
+
if (is.startsWith('=')) { //equal
|
|
210
210
|
range = `[${value} ${value}]`;
|
|
211
211
|
}
|
|
212
|
-
else if (is
|
|
212
|
+
else if (is.startsWith('<')) { //less than or equal
|
|
213
213
|
range = `[-inf ${value}]`;
|
|
214
214
|
}
|
|
215
|
-
else if (is
|
|
215
|
+
else if (is.startsWith('>')) { //greater than or equal
|
|
216
216
|
range = `[${value} +inf]`;
|
|
217
217
|
}
|
|
218
|
-
else if (is === '[]') {
|
|
218
|
+
else if (is === '[]') { //between
|
|
219
219
|
range = `[${value[0]} ${value[1]}]`;
|
|
220
220
|
}
|
|
221
221
|
return `${prefixedFieldName}:${range}`;
|
|
@@ -23,9 +23,10 @@ export declare class Search {
|
|
|
23
23
|
* calling any method that produces side effects (changes the value)
|
|
24
24
|
*/
|
|
25
25
|
getSearchSessionGuid(): string;
|
|
26
|
-
set(
|
|
26
|
+
set(...args: string[]): Promise<void>;
|
|
27
27
|
get(key: string): Promise<string>;
|
|
28
|
-
|
|
28
|
+
mget(...args: string[]): Promise<string[]>;
|
|
29
|
+
del(...args: string[]): Promise<number | void>;
|
|
29
30
|
incr(key: string, val: number): Promise<number>;
|
|
30
31
|
mult(key: string, val: number): Promise<number>;
|
|
31
32
|
}
|
|
@@ -59,12 +59,17 @@ class Search {
|
|
|
59
59
|
//return the search session as it would exist in the search session index
|
|
60
60
|
return `${this.searchSessionId}-${this.searchSessionIndex++}-`;
|
|
61
61
|
}
|
|
62
|
-
async set(
|
|
62
|
+
async set(...args) {
|
|
63
63
|
const ssGuid = this.getSearchSessionGuid();
|
|
64
64
|
const ssGuidValue = Number(await this.store.exec('HINCRBYFLOAT', this.jobId, ssGuid, '1'));
|
|
65
65
|
if (ssGuidValue === 1) {
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
const safeArgs = [];
|
|
67
|
+
for (let i = 0; i < args.length; i += 2) {
|
|
68
|
+
const key = this.safeKey(args[i]);
|
|
69
|
+
const value = args[i + 1].toString();
|
|
70
|
+
safeArgs.push(key, value);
|
|
71
|
+
}
|
|
72
|
+
await this.store.exec('HSET', this.jobId, ...safeArgs);
|
|
68
73
|
}
|
|
69
74
|
}
|
|
70
75
|
async get(key) {
|
|
@@ -76,11 +81,29 @@ class Search {
|
|
|
76
81
|
return '';
|
|
77
82
|
}
|
|
78
83
|
}
|
|
79
|
-
async
|
|
84
|
+
async mget(...args) {
|
|
85
|
+
const safeArgs = [];
|
|
86
|
+
for (let i = 0; i < args.length; i++) {
|
|
87
|
+
safeArgs.push(this.safeKey(args[i]));
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
return await this.store.exec('HMGET', this.jobId, ...safeArgs);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
this.hotMeshClient.logger.error('durable-search-mget-error', { err });
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async del(...args) {
|
|
80
98
|
const ssGuid = this.getSearchSessionGuid();
|
|
81
99
|
const ssGuidValue = Number(await this.store.exec('HINCRBYFLOAT', this.jobId, ssGuid, '1'));
|
|
82
100
|
if (ssGuidValue === 1) {
|
|
83
|
-
|
|
101
|
+
const safeArgs = [];
|
|
102
|
+
for (let i = 0; i < args.length; i++) {
|
|
103
|
+
safeArgs.push(this.safeKey(args[i]));
|
|
104
|
+
}
|
|
105
|
+
const response = await this.store.exec('HDEL', this.jobId, ...safeArgs);
|
|
106
|
+
return isNaN(response) ? undefined : Number(response);
|
|
84
107
|
}
|
|
85
108
|
}
|
|
86
109
|
async incr(key, val) {
|
package/build/types/durable.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -309,13 +309,13 @@ export class MeshOSService {
|
|
|
309
309
|
return `${prefixedFieldName}:"${value}"`;
|
|
310
310
|
case 'NUMERIC':
|
|
311
311
|
let range = '';
|
|
312
|
-
if (is.startsWith('=')) {
|
|
312
|
+
if (is.startsWith('=')) { //equal
|
|
313
313
|
range = `[${value} ${value}]`;
|
|
314
|
-
} else if (is
|
|
314
|
+
} else if (is.startsWith('<')) { //less than or equal
|
|
315
315
|
range = `[-inf ${value}]`;
|
|
316
|
-
} else if (is
|
|
316
|
+
} else if (is.startsWith('>')) { //greater than or equal
|
|
317
317
|
range = `[${value} +inf]`;
|
|
318
|
-
} else if (is === '[]') {
|
|
318
|
+
} else if (is === '[]') { //between
|
|
319
319
|
range = `[${value[0]} ${value[1]}]`
|
|
320
320
|
}
|
|
321
321
|
return `${prefixedFieldName}:${range}`;
|
|
@@ -69,12 +69,17 @@ export class Search {
|
|
|
69
69
|
return `${this.searchSessionId}-${this.searchSessionIndex++}-`;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
async set(
|
|
72
|
+
async set(...args: string[]): Promise<void> {
|
|
73
73
|
const ssGuid = this.getSearchSessionGuid();
|
|
74
74
|
const ssGuidValue = Number(await this.store.exec('HINCRBYFLOAT', this.jobId, ssGuid, '1') as string);
|
|
75
75
|
if (ssGuidValue === 1) {
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
const safeArgs: string[] = [];
|
|
77
|
+
for (let i = 0; i < args.length; i += 2) {
|
|
78
|
+
const key = this.safeKey(args[i]);
|
|
79
|
+
const value = args[i+1].toString();
|
|
80
|
+
safeArgs.push(key, value);
|
|
81
|
+
}
|
|
82
|
+
await this.store.exec('HSET', this.jobId, ...safeArgs);
|
|
78
83
|
}
|
|
79
84
|
}
|
|
80
85
|
|
|
@@ -87,11 +92,29 @@ export class Search {
|
|
|
87
92
|
}
|
|
88
93
|
}
|
|
89
94
|
|
|
90
|
-
async
|
|
95
|
+
async mget(...args: string[]): Promise<string[]> {
|
|
96
|
+
const safeArgs: string[] = [];
|
|
97
|
+
for (let i = 0; i < args.length; i++) {
|
|
98
|
+
safeArgs.push(this.safeKey(args[i]));
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
return await this.store.exec('HMGET', this.jobId, ...safeArgs) as string[];
|
|
102
|
+
} catch (err) {
|
|
103
|
+
this.hotMeshClient.logger.error('durable-search-mget-error', { err });
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async del(...args: string[]): Promise<number | void> {
|
|
91
109
|
const ssGuid = this.getSearchSessionGuid();
|
|
92
110
|
const ssGuidValue = Number(await this.store.exec('HINCRBYFLOAT', this.jobId, ssGuid, '1') as string);
|
|
93
111
|
if (ssGuidValue === 1) {
|
|
94
|
-
|
|
112
|
+
const safeArgs: string[] = [];
|
|
113
|
+
for (let i = 0; i < args.length; i++) {
|
|
114
|
+
safeArgs.push(this.safeKey(args[i]));
|
|
115
|
+
}
|
|
116
|
+
const response = await this.store.exec('HDEL', this.jobId, ...safeArgs);
|
|
117
|
+
return isNaN(response as unknown as number) ? undefined : Number(response);
|
|
95
118
|
}
|
|
96
119
|
}
|
|
97
120
|
|