@hotmeshio/hotmesh 0.4.2 → 0.5.0
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 +226 -47
- package/build/index.d.ts +2 -1
- package/build/index.js +3 -1
- package/build/modules/errors.d.ts +1 -0
- package/build/modules/errors.js +1 -0
- package/build/package.json +4 -3
- package/build/services/activities/trigger.d.ts +1 -1
- package/build/services/activities/trigger.js +6 -3
- package/build/services/memflow/client.js +2 -1
- package/build/services/memflow/{context.d.ts → entity.d.ts} +34 -34
- package/build/services/memflow/{context.js → entity.js} +40 -40
- package/build/services/memflow/index.d.ts +2 -2
- package/build/services/memflow/index.js +2 -2
- package/build/services/memflow/schemas/factory.d.ts +1 -1
- package/build/services/memflow/schemas/factory.js +27 -1
- package/build/services/memflow/worker.js +1 -0
- package/build/services/memflow/workflow/common.d.ts +2 -2
- package/build/services/memflow/workflow/common.js +3 -3
- package/build/services/memflow/workflow/entityMethods.d.ts +14 -0
- package/build/services/memflow/workflow/{contextMethods.js → entityMethods.js} +11 -11
- package/build/services/memflow/workflow/execChild.js +2 -1
- package/build/services/memflow/workflow/index.d.ts +2 -2
- package/build/services/memflow/workflow/index.js +2 -2
- package/build/services/store/index.d.ts +1 -1
- package/build/services/store/providers/postgres/kvsql.d.ts +1 -1
- package/build/services/store/providers/postgres/kvtypes/hash.d.ts +1 -1
- package/build/services/store/providers/postgres/kvtypes/hash.js +8 -8
- package/build/services/store/providers/postgres/postgres.d.ts +1 -1
- package/build/services/store/providers/postgres/postgres.js +3 -2
- package/build/services/store/providers/redis/_base.d.ts +1 -1
- package/build/services/store/providers/redis/_base.js +1 -1
- package/build/types/activity.d.ts +2 -0
- package/build/types/error.d.ts +1 -0
- package/build/types/job.d.ts +7 -0
- package/build/types/provider.d.ts +1 -0
- package/index.ts +2 -2
- package/package.json +4 -3
- package/build/services/memflow/workflow/contextMethods.d.ts +0 -14
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.Entity = void 0;
|
|
4
4
|
const key_1 = require("../../modules/key");
|
|
5
5
|
const storage_1 = require("../../modules/storage");
|
|
6
6
|
/**
|
|
7
|
-
* The
|
|
8
|
-
* JSONB data to a workflow's
|
|
7
|
+
* The Entity module provides methods for reading and writing
|
|
8
|
+
* JSONB data to a workflow's entity. The instance methods
|
|
9
9
|
* exposed by this class are available for use from within
|
|
10
10
|
* a running workflow.
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
13
13
|
* ```typescript
|
|
14
|
-
* //
|
|
14
|
+
* //entityWorkflow.ts
|
|
15
15
|
* import { workflow } from '@hotmeshio/hotmesh';
|
|
16
16
|
*
|
|
17
|
-
* export async function
|
|
18
|
-
* const
|
|
19
|
-
* await
|
|
20
|
-
* await
|
|
21
|
-
* const user = await
|
|
17
|
+
* export async function entityExample(): Promise<void> {
|
|
18
|
+
* const entity = await workflow.entity();
|
|
19
|
+
* await entity.set({ user: { id: 123 } });
|
|
20
|
+
* await entity.merge({ user: { name: "John" } });
|
|
21
|
+
* const user = await entity.get("user");
|
|
22
22
|
* // user = { id: 123, name: "John" }
|
|
23
23
|
* }
|
|
24
24
|
* ```
|
|
25
25
|
*/
|
|
26
|
-
class
|
|
26
|
+
class Entity {
|
|
27
27
|
/**
|
|
28
28
|
* @private
|
|
29
29
|
*/
|
|
@@ -53,11 +53,11 @@ class Context {
|
|
|
53
53
|
return `${this.searchSessionId}-${this.searchSessionIndex++}-`;
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
|
-
* Sets the entire
|
|
56
|
+
* Sets the entire entity object. This replaces any existing entity.
|
|
57
57
|
*
|
|
58
58
|
* @example
|
|
59
|
-
* const
|
|
60
|
-
* await
|
|
59
|
+
* const entity = await workflow.entity();
|
|
60
|
+
* await entity.set({ user: { id: 123, name: "John" } });
|
|
61
61
|
*/
|
|
62
62
|
async set(value) {
|
|
63
63
|
const ssGuid = this.getSearchSessionGuid();
|
|
@@ -66,7 +66,7 @@ class Context {
|
|
|
66
66
|
if (ssGuid in replay) {
|
|
67
67
|
return JSON.parse(replay[ssGuid]);
|
|
68
68
|
}
|
|
69
|
-
// Use single transactional call to update
|
|
69
|
+
// Use single transactional call to update entity and store replay value
|
|
70
70
|
const result = await this.search.updateContext(this.jobId, {
|
|
71
71
|
'@context': JSON.stringify(value),
|
|
72
72
|
[ssGuid]: '', // Pass replay ID to hash module for transactional replay storage
|
|
@@ -74,11 +74,11 @@ class Context {
|
|
|
74
74
|
return result || value;
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
77
|
-
* Deep merges the provided object with the existing
|
|
77
|
+
* Deep merges the provided object with the existing entity
|
|
78
78
|
*
|
|
79
79
|
* @example
|
|
80
|
-
* const
|
|
81
|
-
* await
|
|
80
|
+
* const entity = await workflow.entity();
|
|
81
|
+
* await entity.merge({ user: { email: "john@example.com" } });
|
|
82
82
|
*/
|
|
83
83
|
async merge(value) {
|
|
84
84
|
const ssGuid = this.getSearchSessionGuid();
|
|
@@ -95,29 +95,29 @@ class Context {
|
|
|
95
95
|
return newContext;
|
|
96
96
|
}
|
|
97
97
|
/**
|
|
98
|
-
* Gets a value from the
|
|
98
|
+
* Gets a value from the entity by path
|
|
99
99
|
*
|
|
100
100
|
* @example
|
|
101
|
-
* const
|
|
102
|
-
* const user = await
|
|
103
|
-
* const email = await
|
|
101
|
+
* const entity = await workflow.entity();
|
|
102
|
+
* const user = await entity.get("user");
|
|
103
|
+
* const email = await entity.get("user.email");
|
|
104
104
|
*/
|
|
105
105
|
async get(path) {
|
|
106
106
|
const ssGuid = this.getSearchSessionGuid();
|
|
107
107
|
const store = storage_1.asyncLocalStorage.getStore();
|
|
108
108
|
const replay = store?.get('replay') ?? {};
|
|
109
109
|
if (ssGuid in replay) {
|
|
110
|
-
// Replay cache stores the already-extracted value, not full
|
|
110
|
+
// Replay cache stores the already-extracted value, not full entity
|
|
111
111
|
return JSON.parse(replay[ssGuid]);
|
|
112
112
|
}
|
|
113
113
|
let value;
|
|
114
114
|
if (!path) {
|
|
115
|
-
// No path - fetch entire
|
|
115
|
+
// No path - fetch entire entity with replay storage
|
|
116
116
|
const result = await this.search.updateContext(this.jobId, {
|
|
117
117
|
'@context:get': '',
|
|
118
118
|
[ssGuid]: '', // Pass replay ID to hash module
|
|
119
119
|
});
|
|
120
|
-
// setFields returns the actual
|
|
120
|
+
// setFields returns the actual entity value for @context:get operations
|
|
121
121
|
value = result || {};
|
|
122
122
|
}
|
|
123
123
|
else {
|
|
@@ -132,11 +132,11 @@ class Context {
|
|
|
132
132
|
return value;
|
|
133
133
|
}
|
|
134
134
|
/**
|
|
135
|
-
* Deletes a value from the
|
|
135
|
+
* Deletes a value from the entity by path
|
|
136
136
|
*
|
|
137
137
|
* @example
|
|
138
|
-
* const
|
|
139
|
-
* await
|
|
138
|
+
* const entity = await workflow.entity();
|
|
139
|
+
* await entity.delete("user.email");
|
|
140
140
|
*/
|
|
141
141
|
async delete(path) {
|
|
142
142
|
const ssGuid = this.getSearchSessionGuid();
|
|
@@ -156,8 +156,8 @@ class Context {
|
|
|
156
156
|
* Appends a value to an array at the specified path
|
|
157
157
|
*
|
|
158
158
|
* @example
|
|
159
|
-
* const
|
|
160
|
-
* await
|
|
159
|
+
* const entity = await workflow.entity();
|
|
160
|
+
* await entity.append("items", { id: 1, name: "New Item" });
|
|
161
161
|
*/
|
|
162
162
|
async append(path, value) {
|
|
163
163
|
const ssGuid = this.getSearchSessionGuid();
|
|
@@ -177,8 +177,8 @@ class Context {
|
|
|
177
177
|
* Prepends a value to an array at the specified path
|
|
178
178
|
*
|
|
179
179
|
* @example
|
|
180
|
-
* const
|
|
181
|
-
* await
|
|
180
|
+
* const entity = await workflow.entity();
|
|
181
|
+
* await entity.prepend("items", { id: 0, name: "First Item" });
|
|
182
182
|
*/
|
|
183
183
|
async prepend(path, value) {
|
|
184
184
|
const ssGuid = this.getSearchSessionGuid();
|
|
@@ -198,8 +198,8 @@ class Context {
|
|
|
198
198
|
* Removes an item from an array at the specified path and index
|
|
199
199
|
*
|
|
200
200
|
* @example
|
|
201
|
-
* const
|
|
202
|
-
* await
|
|
201
|
+
* const entity = await workflow.entity();
|
|
202
|
+
* await entity.remove("items", 0); // Remove first item
|
|
203
203
|
*/
|
|
204
204
|
async remove(path, index) {
|
|
205
205
|
const ssGuid = this.getSearchSessionGuid();
|
|
@@ -219,8 +219,8 @@ class Context {
|
|
|
219
219
|
* Increments a numeric value at the specified path
|
|
220
220
|
*
|
|
221
221
|
* @example
|
|
222
|
-
* const
|
|
223
|
-
* await
|
|
222
|
+
* const entity = await workflow.entity();
|
|
223
|
+
* await entity.increment("counter", 5);
|
|
224
224
|
*/
|
|
225
225
|
async increment(path, value = 1) {
|
|
226
226
|
const ssGuid = this.getSearchSessionGuid();
|
|
@@ -240,8 +240,8 @@ class Context {
|
|
|
240
240
|
* Toggles a boolean value at the specified path
|
|
241
241
|
*
|
|
242
242
|
* @example
|
|
243
|
-
* const
|
|
244
|
-
* await
|
|
243
|
+
* const entity = await workflow.entity();
|
|
244
|
+
* await entity.toggle("settings.enabled");
|
|
245
245
|
*/
|
|
246
246
|
async toggle(path) {
|
|
247
247
|
const ssGuid = this.getSearchSessionGuid();
|
|
@@ -261,8 +261,8 @@ class Context {
|
|
|
261
261
|
* Sets a value at the specified path only if it doesn't already exist
|
|
262
262
|
*
|
|
263
263
|
* @example
|
|
264
|
-
* const
|
|
265
|
-
* await
|
|
264
|
+
* const entity = await workflow.entity();
|
|
265
|
+
* await entity.setIfNotExists("user.id", 123);
|
|
266
266
|
*/
|
|
267
267
|
async setIfNotExists(path, value) {
|
|
268
268
|
const ssGuid = this.getSearchSessionGuid();
|
|
@@ -296,4 +296,4 @@ class Context {
|
|
|
296
296
|
return output;
|
|
297
297
|
}
|
|
298
298
|
}
|
|
299
|
-
exports.
|
|
299
|
+
exports.Entity = Entity;
|
|
@@ -2,7 +2,7 @@ import { ContextType } from '../../types/memflow';
|
|
|
2
2
|
import { ClientService } from './client';
|
|
3
3
|
import { ConnectionService } from './connection';
|
|
4
4
|
import { Search } from './search';
|
|
5
|
-
import {
|
|
5
|
+
import { Entity } from './entity';
|
|
6
6
|
import { WorkerService } from './worker';
|
|
7
7
|
import { WorkflowService } from './workflow';
|
|
8
8
|
import { WorkflowHandleService } from './handle';
|
|
@@ -86,7 +86,7 @@ declare class MemFlowClass {
|
|
|
86
86
|
/**
|
|
87
87
|
* @private
|
|
88
88
|
*/
|
|
89
|
-
static
|
|
89
|
+
static Entity: typeof Entity;
|
|
90
90
|
/**
|
|
91
91
|
* The Handle provides methods to interact with a running
|
|
92
92
|
* workflow. This includes exporting the workflow, sending signals, and
|
|
@@ -5,7 +5,7 @@ const hotmesh_1 = require("../hotmesh");
|
|
|
5
5
|
const client_1 = require("./client");
|
|
6
6
|
const connection_1 = require("./connection");
|
|
7
7
|
const search_1 = require("./search");
|
|
8
|
-
const
|
|
8
|
+
const entity_1 = require("./entity");
|
|
9
9
|
const worker_1 = require("./worker");
|
|
10
10
|
const workflow_1 = require("./workflow");
|
|
11
11
|
const handle_1 = require("./handle");
|
|
@@ -100,7 +100,7 @@ MemFlowClass.Search = search_1.Search;
|
|
|
100
100
|
/**
|
|
101
101
|
* @private
|
|
102
102
|
*/
|
|
103
|
-
MemFlowClass.
|
|
103
|
+
MemFlowClass.Entity = entity_1.Entity;
|
|
104
104
|
/**
|
|
105
105
|
* The Handle provides methods to interact with a running
|
|
106
106
|
* workflow. This includes exporting the workflow, sending signals, and
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
22
|
exports.APP_ID = exports.APP_VERSION = exports.getWorkflowYAML = void 0;
|
|
23
|
-
const APP_VERSION = '
|
|
23
|
+
const APP_VERSION = '5';
|
|
24
24
|
exports.APP_VERSION = APP_VERSION;
|
|
25
25
|
const APP_ID = 'memflow';
|
|
26
26
|
exports.APP_ID = APP_ID;
|
|
@@ -86,6 +86,9 @@ const getWorkflowYAML = (app, version) => {
|
|
|
86
86
|
signalIn:
|
|
87
87
|
description: if false, the job will not support subordinated hooks
|
|
88
88
|
type: boolean
|
|
89
|
+
entity:
|
|
90
|
+
description: the entity type for this workflow instance
|
|
91
|
+
type: string
|
|
89
92
|
|
|
90
93
|
output:
|
|
91
94
|
schema:
|
|
@@ -120,6 +123,7 @@ const getWorkflowYAML = (app, version) => {
|
|
|
120
123
|
trigger:
|
|
121
124
|
title: Main Flow Trigger
|
|
122
125
|
type: trigger
|
|
126
|
+
entity: '{$self.input.data.entity}'
|
|
123
127
|
job:
|
|
124
128
|
maps:
|
|
125
129
|
done: false
|
|
@@ -249,6 +253,9 @@ const getWorkflowYAML = (app, version) => {
|
|
|
249
253
|
await:
|
|
250
254
|
type: string
|
|
251
255
|
description: when set to false, do not await the child flow's completion
|
|
256
|
+
entity:
|
|
257
|
+
type: string
|
|
258
|
+
description: the entity type for the child workflow
|
|
252
259
|
591:
|
|
253
260
|
schema:
|
|
254
261
|
type: object
|
|
@@ -367,6 +374,9 @@ const getWorkflowYAML = (app, version) => {
|
|
|
367
374
|
description: the arguments to pass to the activity
|
|
368
375
|
items:
|
|
369
376
|
type: string
|
|
377
|
+
entity:
|
|
378
|
+
type: string
|
|
379
|
+
description: the entity type for the child workflow
|
|
370
380
|
maps:
|
|
371
381
|
arguments: '{worker.output.data.arguments}'
|
|
372
382
|
workflowDimension: '{worker.output.data.workflowDimension}'
|
|
@@ -379,6 +389,7 @@ const getWorkflowYAML = (app, version) => {
|
|
|
379
389
|
workflowId: '{worker.output.data.workflowId}'
|
|
380
390
|
workflowName: '{worker.output.data.workflowName}'
|
|
381
391
|
workflowTopic: '{worker.output.data.workflowTopic}'
|
|
392
|
+
entity: '{worker.output.data.entity}'
|
|
382
393
|
backoffCoefficient:
|
|
383
394
|
'@pipe':
|
|
384
395
|
- ['{worker.output.data.backoffCoefficient}','{trigger.output.data.backoffCoefficient}']
|
|
@@ -992,6 +1003,9 @@ const getWorkflowYAML = (app, version) => {
|
|
|
992
1003
|
await:
|
|
993
1004
|
type: string
|
|
994
1005
|
description: when set to false, do not await the child flow's completion
|
|
1006
|
+
entity:
|
|
1007
|
+
type: string
|
|
1008
|
+
description: the entity type for the child workflow
|
|
995
1009
|
591:
|
|
996
1010
|
schema:
|
|
997
1011
|
type: object
|
|
@@ -1109,6 +1123,9 @@ const getWorkflowYAML = (app, version) => {
|
|
|
1109
1123
|
description: the arguments to pass to the activity
|
|
1110
1124
|
items:
|
|
1111
1125
|
type: string
|
|
1126
|
+
entity:
|
|
1127
|
+
type: string
|
|
1128
|
+
description: the entity type for the child workflow
|
|
1112
1129
|
maps:
|
|
1113
1130
|
arguments: '{signaler_worker.output.data.arguments}'
|
|
1114
1131
|
workflowDimension: '{signaler_worker.output.data.workflowDimension}'
|
|
@@ -1121,6 +1138,7 @@ const getWorkflowYAML = (app, version) => {
|
|
|
1121
1138
|
workflowId: '{signaler_worker.output.data.workflowId}'
|
|
1122
1139
|
workflowName: '{signaler_worker.output.data.workflowName}'
|
|
1123
1140
|
workflowTopic: '{signaler_worker.output.data.workflowTopic}'
|
|
1141
|
+
entity: '{signaler_worker.output.data.entity}'
|
|
1124
1142
|
backoffCoefficient:
|
|
1125
1143
|
'@pipe':
|
|
1126
1144
|
- ['{signaler_worker.output.data.backoffCoefficient}','{trigger.output.data.backoffCoefficient}']
|
|
@@ -1875,6 +1893,9 @@ const getWorkflowYAML = (app, version) => {
|
|
|
1875
1893
|
description: the arguments to pass to the activity
|
|
1876
1894
|
items:
|
|
1877
1895
|
type: string
|
|
1896
|
+
entity:
|
|
1897
|
+
type: string
|
|
1898
|
+
description: the entity type for the child workflow
|
|
1878
1899
|
maps:
|
|
1879
1900
|
arguments:
|
|
1880
1901
|
'@pipe':
|
|
@@ -1946,6 +1967,11 @@ const getWorkflowYAML = (app, version) => {
|
|
|
1946
1967
|
- ['{collator_trigger.output.data.items}', '{collator_cycle_hook.output.data.cur_index}']
|
|
1947
1968
|
- ['{@array.get}', maximumInterval]
|
|
1948
1969
|
- ['{@object.get}']
|
|
1970
|
+
entity:
|
|
1971
|
+
'@pipe':
|
|
1972
|
+
- ['{collator_trigger.output.data.items}', '{collator_cycle_hook.output.data.cur_index}']
|
|
1973
|
+
- ['{@array.get}', entity]
|
|
1974
|
+
- ['{@object.get}']
|
|
1949
1975
|
output:
|
|
1950
1976
|
schema:
|
|
1951
1977
|
type: object
|
|
@@ -431,6 +431,7 @@ class WorkerService {
|
|
|
431
431
|
maximumAttempts: err.maximumAttempts || enums_1.HMSH_MEMFLOW_MAX_ATTEMPTS,
|
|
432
432
|
maximumInterval: err.maximumInterval || (0, utils_1.s)(enums_1.HMSH_MEMFLOW_MAX_INTERVAL),
|
|
433
433
|
originJobId: err.originJobId,
|
|
434
|
+
entity: err.entity,
|
|
434
435
|
parentWorkflowId: err.parentWorkflowId,
|
|
435
436
|
expire: err.expire,
|
|
436
437
|
persistent: err.persistent,
|
|
@@ -15,6 +15,6 @@ import { QuorumMessage } from '../../../types';
|
|
|
15
15
|
import { UserMessage } from '../../../types/quorum';
|
|
16
16
|
import { Search } from '../search';
|
|
17
17
|
import { WorkerService } from '../worker';
|
|
18
|
-
import {
|
|
18
|
+
import { Entity } from '../entity';
|
|
19
19
|
import { ExecHookOptions } from './execHook';
|
|
20
|
-
export { MemFlowChildError, MemFlowFatalError, MemFlowMaxedError, MemFlowProxyError, MemFlowRetryError, MemFlowSleepError, MemFlowTimeoutError, MemFlowWaitForError, KeyService, KeyType, asyncLocalStorage, deterministicRandom, guid, s, sleepImmediate, HotMesh, SerializerService, ActivityConfig, ChildResponseType, HookOptions, ExecHookOptions, ProxyResponseType, ProxyType, WorkflowContext, WorkflowOptions, JobInterruptOptions, StreamCode, StreamStatus, StringAnyType, StringScalarType, StringStringType, HMSH_CODE_MEMFLOW_CHILD, HMSH_CODE_MEMFLOW_FATAL, HMSH_CODE_MEMFLOW_MAXED, HMSH_CODE_MEMFLOW_PROXY, HMSH_CODE_MEMFLOW_SLEEP, HMSH_CODE_MEMFLOW_TIMEOUT, HMSH_CODE_MEMFLOW_WAIT, HMSH_MEMFLOW_EXP_BACKOFF, HMSH_MEMFLOW_MAX_ATTEMPTS, HMSH_MEMFLOW_MAX_INTERVAL, MemFlowChildErrorType, MemFlowProxyErrorType, TelemetryService, QuorumMessage, UserMessage, Search, WorkerService,
|
|
20
|
+
export { MemFlowChildError, MemFlowFatalError, MemFlowMaxedError, MemFlowProxyError, MemFlowRetryError, MemFlowSleepError, MemFlowTimeoutError, MemFlowWaitForError, KeyService, KeyType, asyncLocalStorage, deterministicRandom, guid, s, sleepImmediate, HotMesh, SerializerService, ActivityConfig, ChildResponseType, HookOptions, ExecHookOptions, ProxyResponseType, ProxyType, WorkflowContext, WorkflowOptions, JobInterruptOptions, StreamCode, StreamStatus, StringAnyType, StringScalarType, StringStringType, HMSH_CODE_MEMFLOW_CHILD, HMSH_CODE_MEMFLOW_FATAL, HMSH_CODE_MEMFLOW_MAXED, HMSH_CODE_MEMFLOW_PROXY, HMSH_CODE_MEMFLOW_SLEEP, HMSH_CODE_MEMFLOW_TIMEOUT, HMSH_CODE_MEMFLOW_WAIT, HMSH_MEMFLOW_EXP_BACKOFF, HMSH_MEMFLOW_MAX_ATTEMPTS, HMSH_MEMFLOW_MAX_INTERVAL, MemFlowChildErrorType, MemFlowProxyErrorType, TelemetryService, QuorumMessage, UserMessage, Search, WorkerService, Entity, };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.Entity = exports.WorkerService = exports.Search = exports.TelemetryService = exports.HMSH_MEMFLOW_MAX_INTERVAL = exports.HMSH_MEMFLOW_MAX_ATTEMPTS = exports.HMSH_MEMFLOW_EXP_BACKOFF = exports.HMSH_CODE_MEMFLOW_WAIT = exports.HMSH_CODE_MEMFLOW_TIMEOUT = exports.HMSH_CODE_MEMFLOW_SLEEP = exports.HMSH_CODE_MEMFLOW_PROXY = exports.HMSH_CODE_MEMFLOW_MAXED = exports.HMSH_CODE_MEMFLOW_FATAL = exports.HMSH_CODE_MEMFLOW_CHILD = exports.StreamStatus = exports.SerializerService = exports.HotMesh = exports.sleepImmediate = exports.s = exports.guid = exports.deterministicRandom = exports.asyncLocalStorage = exports.KeyType = exports.KeyService = exports.MemFlowWaitForError = exports.MemFlowTimeoutError = exports.MemFlowSleepError = exports.MemFlowRetryError = exports.MemFlowProxyError = exports.MemFlowMaxedError = exports.MemFlowFatalError = exports.MemFlowChildError = void 0;
|
|
4
4
|
const errors_1 = require("../../../modules/errors");
|
|
5
5
|
Object.defineProperty(exports, "MemFlowChildError", { enumerable: true, get: function () { return errors_1.MemFlowChildError; } });
|
|
6
6
|
Object.defineProperty(exports, "MemFlowFatalError", { enumerable: true, get: function () { return errors_1.MemFlowFatalError; } });
|
|
@@ -43,5 +43,5 @@ const search_1 = require("../search");
|
|
|
43
43
|
Object.defineProperty(exports, "Search", { enumerable: true, get: function () { return search_1.Search; } });
|
|
44
44
|
const worker_1 = require("../worker");
|
|
45
45
|
Object.defineProperty(exports, "WorkerService", { enumerable: true, get: function () { return worker_1.WorkerService; } });
|
|
46
|
-
const
|
|
47
|
-
Object.defineProperty(exports, "
|
|
46
|
+
const entity_1 = require("../entity");
|
|
47
|
+
Object.defineProperty(exports, "Entity", { enumerable: true, get: function () { return entity_1.Entity; } });
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Entity } from './common';
|
|
2
|
+
/**
|
|
3
|
+
* Returns an entity session handle for interacting with the workflow's JSONB entity storage.
|
|
4
|
+
* @returns {Promise<Entity>} An entity session for workflow data.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* const entity = await workflow.entity();
|
|
9
|
+
* await entity.set({ user: { id: 123 } });
|
|
10
|
+
* await entity.merge({ user: { name: "John" } });
|
|
11
|
+
* const user = await entity.get("user");
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare function entity(): Promise<Entity>;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.entity = void 0;
|
|
4
4
|
const common_1 = require("./common");
|
|
5
5
|
/**
|
|
6
|
-
* Returns
|
|
7
|
-
* @returns {Promise<
|
|
6
|
+
* Returns an entity session handle for interacting with the workflow's JSONB entity storage.
|
|
7
|
+
* @returns {Promise<Entity>} An entity session for workflow data.
|
|
8
8
|
*
|
|
9
9
|
* @example
|
|
10
10
|
* ```typescript
|
|
11
|
-
* const
|
|
12
|
-
* await
|
|
13
|
-
* await
|
|
14
|
-
* const user = await
|
|
11
|
+
* const entity = await workflow.entity();
|
|
12
|
+
* await entity.set({ user: { id: 123 } });
|
|
13
|
+
* await entity.merge({ user: { name: "John" } });
|
|
14
|
+
* const user = await entity.get("user");
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
|
-
async function
|
|
17
|
+
async function entity() {
|
|
18
18
|
const store = common_1.asyncLocalStorage.getStore();
|
|
19
19
|
const workflowId = store.get('workflowId');
|
|
20
20
|
const workflowDimension = store.get('workflowDimension') ?? '';
|
|
@@ -27,7 +27,7 @@ async function context() {
|
|
|
27
27
|
connection,
|
|
28
28
|
namespace,
|
|
29
29
|
});
|
|
30
|
-
const
|
|
31
|
-
return new common_1.
|
|
30
|
+
const entitySessionId = `-entity${workflowDimension}-${execIndex}`;
|
|
31
|
+
return new common_1.Entity(workflowId, hotMeshClient, entitySessionId);
|
|
32
32
|
}
|
|
33
|
-
exports.
|
|
33
|
+
exports.entity = entity;
|
|
@@ -22,7 +22,7 @@ function getChildInterruptPayload(context, options, execIndex) {
|
|
|
22
22
|
}
|
|
23
23
|
const parentWorkflowId = workflowId;
|
|
24
24
|
const taskQueueName = options.taskQueue ?? options.entity;
|
|
25
|
-
const workflowName = options.entity ?? options.workflowName;
|
|
25
|
+
const workflowName = options.taskQueue ? options.workflowName : (options.entity ?? options.workflowName);
|
|
26
26
|
const workflowTopic = `${taskQueueName}-${workflowName}`;
|
|
27
27
|
return {
|
|
28
28
|
arguments: [...(options.args || [])],
|
|
@@ -32,6 +32,7 @@ function getChildInterruptPayload(context, options, execIndex) {
|
|
|
32
32
|
maximumAttempts: options?.config?.maximumAttempts ?? common_1.HMSH_MEMFLOW_MAX_ATTEMPTS,
|
|
33
33
|
maximumInterval: (0, common_1.s)(options?.config?.maximumInterval ?? common_1.HMSH_MEMFLOW_MAX_INTERVAL),
|
|
34
34
|
originJobId: originJobId ?? workflowId,
|
|
35
|
+
entity: options.entity,
|
|
35
36
|
expire: options.expire ?? expire,
|
|
36
37
|
persistent: options.persistent,
|
|
37
38
|
signalIn: options.signalIn,
|
|
@@ -16,7 +16,7 @@ import { all } from './all';
|
|
|
16
16
|
import { sleepFor } from './sleepFor';
|
|
17
17
|
import { waitFor } from './waitFor';
|
|
18
18
|
import { HotMesh } from './common';
|
|
19
|
-
import {
|
|
19
|
+
import { entity } from './entityMethods';
|
|
20
20
|
/**
|
|
21
21
|
* The WorkflowService class provides a set of static methods to be used within a workflow function.
|
|
22
22
|
* These methods ensure deterministic replay, persistence of state, and error handling across
|
|
@@ -58,7 +58,7 @@ export declare class WorkflowService {
|
|
|
58
58
|
static execHook: typeof execHook;
|
|
59
59
|
static proxyActivities: typeof proxyActivities;
|
|
60
60
|
static search: typeof search;
|
|
61
|
-
static
|
|
61
|
+
static entity: typeof entity;
|
|
62
62
|
static random: typeof random;
|
|
63
63
|
static signal: typeof signal;
|
|
64
64
|
static hook: typeof hook;
|
|
@@ -19,7 +19,7 @@ const all_1 = require("./all");
|
|
|
19
19
|
const sleepFor_1 = require("./sleepFor");
|
|
20
20
|
const waitFor_1 = require("./waitFor");
|
|
21
21
|
const common_1 = require("./common");
|
|
22
|
-
const
|
|
22
|
+
const entityMethods_1 = require("./entityMethods");
|
|
23
23
|
/**
|
|
24
24
|
* The WorkflowService class provides a set of static methods to be used within a workflow function.
|
|
25
25
|
* These methods ensure deterministic replay, persistence of state, and error handling across
|
|
@@ -76,7 +76,7 @@ WorkflowService.startChild = execChild_1.startChild;
|
|
|
76
76
|
WorkflowService.execHook = execHook_1.execHook;
|
|
77
77
|
WorkflowService.proxyActivities = proxyActivities_1.proxyActivities;
|
|
78
78
|
WorkflowService.search = searchMethods_1.search;
|
|
79
|
-
WorkflowService.
|
|
79
|
+
WorkflowService.entity = entityMethods_1.entity;
|
|
80
80
|
WorkflowService.random = random_1.random;
|
|
81
81
|
WorkflowService.signal = signal_1.signal;
|
|
82
82
|
WorkflowService.hook = hook_1.hook;
|
|
@@ -40,7 +40,7 @@ declare abstract class StoreService<Provider extends ProviderClient, Transaction
|
|
|
40
40
|
abstract getJobIds(indexKeys: string[], idRange: [number, number]): Promise<IdsData>;
|
|
41
41
|
abstract setStatus(collationKeyStatus: number, jobId: string, appId: string, transaction?: TransactionProvider): Promise<any>;
|
|
42
42
|
abstract getStatus(jobId: string, appId: string): Promise<number>;
|
|
43
|
-
abstract setStateNX(jobId: string, appId: string, status?: number): Promise<boolean>;
|
|
43
|
+
abstract setStateNX(jobId: string, appId: string, status?: number, entity?: string): Promise<boolean>;
|
|
44
44
|
abstract setState(state: StringAnyType, status: number | null, jobId: string, symbolNames: string[], dIds: StringStringType, transaction?: TransactionProvider): Promise<string>;
|
|
45
45
|
abstract getQueryState(jobId: string, fields: string[]): Promise<StringAnyType>;
|
|
46
46
|
abstract getState(jobId: string, consumes: Consumes, dIds: StringStringType): Promise<[StringAnyType, number] | undefined>;
|
|
@@ -52,7 +52,7 @@ export declare class KVSQL {
|
|
|
52
52
|
sql: string;
|
|
53
53
|
params: any[];
|
|
54
54
|
};
|
|
55
|
-
hsetnx: (key: string, field: string, value: string, multi?: ProviderTransaction) => Promise<number>;
|
|
55
|
+
hsetnx: (key: string, field: string, value: string, multi?: ProviderTransaction, entity?: string) => Promise<number>;
|
|
56
56
|
hget: (key: string, field: string, multi?: ProviderTransaction) => Promise<string>;
|
|
57
57
|
_hget: (key: string, field: string) => {
|
|
58
58
|
sql: string;
|
|
@@ -2,7 +2,7 @@ import { PostgresJobEnumType } from '../../../../../types/postgres';
|
|
|
2
2
|
import { HScanResult, HSetOptions, ProviderTransaction } from '../../../../../types/provider';
|
|
3
3
|
import type { KVSQL } from '../kvsql';
|
|
4
4
|
export declare const hashModule: (context: KVSQL) => {
|
|
5
|
-
hsetnx(key: string, field: string, value: string, multi?: ProviderTransaction): Promise<number>;
|
|
5
|
+
hsetnx(key: string, field: string, value: string, multi?: ProviderTransaction, entity?: string): Promise<number>;
|
|
6
6
|
hset(key: string, fields: Record<string, string>, options?: HSetOptions, multi?: ProviderTransaction): Promise<number | any>;
|
|
7
7
|
/**
|
|
8
8
|
* Derives the enumerated `type` value based on the field name when
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.hashModule = void 0;
|
|
4
4
|
const hashModule = (context) => ({
|
|
5
|
-
async hsetnx(key, field, value, multi) {
|
|
6
|
-
const { sql, params } = this._hset(key, { [field]: value }, { nx: true });
|
|
5
|
+
async hsetnx(key, field, value, multi, entity) {
|
|
6
|
+
const { sql, params } = this._hset(key, { [field]: value }, { nx: true, entity });
|
|
7
7
|
if (multi) {
|
|
8
8
|
multi.addCommand(sql, params, 'number');
|
|
9
9
|
return Promise.resolve(0);
|
|
@@ -97,25 +97,25 @@ const hashModule = (context) => ({
|
|
|
97
97
|
if (options?.nx) {
|
|
98
98
|
// Use WHERE NOT EXISTS to enforce nx
|
|
99
99
|
sql = `
|
|
100
|
-
INSERT INTO ${targetTable} (id, key, status)
|
|
101
|
-
SELECT gen_random_uuid(), $1, $2
|
|
100
|
+
INSERT INTO ${targetTable} (id, key, status, entity)
|
|
101
|
+
SELECT gen_random_uuid(), $1, $2, $3
|
|
102
102
|
WHERE NOT EXISTS (
|
|
103
103
|
SELECT 1 FROM ${targetTable}
|
|
104
104
|
WHERE key = $1 AND is_live
|
|
105
105
|
)
|
|
106
106
|
RETURNING 1 as count
|
|
107
107
|
`;
|
|
108
|
-
params.push(key, fields[':']);
|
|
108
|
+
params.push(key, fields[':'], options?.entity ?? null);
|
|
109
109
|
}
|
|
110
110
|
else {
|
|
111
111
|
// Update existing job or insert new one
|
|
112
112
|
sql = `
|
|
113
|
-
INSERT INTO ${targetTable} (id, key, status)
|
|
114
|
-
VALUES (gen_random_uuid(), $1, $2)
|
|
113
|
+
INSERT INTO ${targetTable} (id, key, status, entity)
|
|
114
|
+
VALUES (gen_random_uuid(), $1, $2, $3)
|
|
115
115
|
ON CONFLICT (key) WHERE is_live DO UPDATE SET status = EXCLUDED.status
|
|
116
116
|
RETURNING 1 as count
|
|
117
117
|
`;
|
|
118
|
-
params.push(key, fields[':']);
|
|
118
|
+
params.push(key, fields[':'], options?.entity ?? null);
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
else if (isJobsTable && '@context' in fields) {
|
|
@@ -83,7 +83,7 @@ declare class PostgresStoreService extends StoreService<ProviderClient, Provider
|
|
|
83
83
|
* `purposeful re-entry`.
|
|
84
84
|
*/
|
|
85
85
|
collateSynthetic(jobId: string, guid: string, amount: number, transaction?: ProviderTransaction): Promise<number>;
|
|
86
|
-
setStateNX(jobId: string, appId: string, status?: number): Promise<boolean>;
|
|
86
|
+
setStateNX(jobId: string, appId: string, status?: number, entity?: string): Promise<boolean>;
|
|
87
87
|
getSchema(activityId: string, appVersion: AppVID): Promise<ActivityType>;
|
|
88
88
|
getSchemas(appVersion: AppVID): Promise<Record<string, ActivityType>>;
|
|
89
89
|
setSchemas(schemas: Record<string, ActivityType>, appVersion: AppVID): Promise<any>;
|
|
@@ -567,9 +567,10 @@ class PostgresStoreService extends __1.StoreService {
|
|
|
567
567
|
});
|
|
568
568
|
return await this.kvsql(transaction).hincrbyfloat(jobKey, guid, amount);
|
|
569
569
|
}
|
|
570
|
-
async setStateNX(jobId, appId, status) {
|
|
570
|
+
async setStateNX(jobId, appId, status, entity) {
|
|
571
571
|
const hashKey = this.mintKey(key_1.KeyType.JOB_STATE, { appId, jobId });
|
|
572
|
-
const result = await this.kvsql().hsetnx(hashKey, ':', status?.toString() ?? '1'
|
|
572
|
+
const result = await this.kvsql().hsetnx(hashKey, ':', status?.toString() ?? '1', undefined, //multi
|
|
573
|
+
entity);
|
|
573
574
|
return this.isSuccessful(result);
|
|
574
575
|
}
|
|
575
576
|
async getSchema(activityId, appVersion) {
|
|
@@ -75,7 +75,7 @@ declare abstract class RedisStoreBase<ClientProvider extends ProviderClient, Tra
|
|
|
75
75
|
* `purposeful re-entry`.
|
|
76
76
|
*/
|
|
77
77
|
collateSynthetic(jobId: string, guid: string, amount: number, transaction?: TransactionProvider): Promise<number>;
|
|
78
|
-
setStateNX(jobId: string, appId: string, status?: number): Promise<boolean>;
|
|
78
|
+
setStateNX(jobId: string, appId: string, status?: number, entity?: string): Promise<boolean>;
|
|
79
79
|
getSchema(activityId: string, appVersion: AppVID): Promise<ActivityType>;
|
|
80
80
|
getSchemas(appVersion: AppVID): Promise<Record<string, ActivityType>>;
|
|
81
81
|
setSchemas(schemas: Record<string, ActivityType>, appVersion: AppVID): Promise<any>;
|
|
@@ -539,7 +539,7 @@ class RedisStoreBase extends __1.StoreService {
|
|
|
539
539
|
});
|
|
540
540
|
return await (transaction || this.storeClient)[this.commands.hincrbyfloat](jobKey, guid, amount.toString());
|
|
541
541
|
}
|
|
542
|
-
async setStateNX(jobId, appId, status) {
|
|
542
|
+
async setStateNX(jobId, appId, status, entity) {
|
|
543
543
|
const hashKey = this.mintKey(key_1.KeyType.JOB_STATE, { appId, jobId });
|
|
544
544
|
const result = await this.storeClient[this.commands.hsetnx](hashKey, ':', status?.toString() ?? '1');
|
|
545
545
|
return this.isSuccessful(result);
|
|
@@ -9,6 +9,7 @@ interface BaseActivity {
|
|
|
9
9
|
statusThreshold?: number;
|
|
10
10
|
statusThresholdType?: 'stop' | 'throw' | 'stall';
|
|
11
11
|
input?: Record<string, any>;
|
|
12
|
+
entity?: string;
|
|
12
13
|
output?: Record<string, any>;
|
|
13
14
|
settings?: Record<string, any>;
|
|
14
15
|
job?: Record<string, any>;
|
|
@@ -73,6 +74,7 @@ interface TriggerActivityStats {
|
|
|
73
74
|
interface TriggerActivity extends BaseActivity {
|
|
74
75
|
type: 'trigger';
|
|
75
76
|
stats?: TriggerActivityStats;
|
|
77
|
+
entity?: string;
|
|
76
78
|
}
|
|
77
79
|
interface AwaitActivity extends BaseActivity {
|
|
78
80
|
type: 'await';
|