@hotmeshio/hotmesh 0.0.34 → 0.0.36
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 +30 -18
- package/build/modules/enums.d.ts +22 -0
- package/build/modules/enums.js +29 -0
- package/build/modules/errors.d.ts +10 -2
- package/build/modules/errors.js +14 -3
- package/build/modules/key.d.ts +16 -15
- package/build/modules/key.js +18 -15
- package/build/modules/utils.d.ts +1 -0
- package/build/modules/utils.js +6 -1
- package/build/package.json +3 -1
- package/build/services/activities/activity.d.ts +5 -0
- package/build/services/activities/activity.js +27 -6
- package/build/services/activities/await.js +11 -3
- package/build/services/activities/cycle.js +10 -2
- package/build/services/activities/hook.js +8 -2
- package/build/services/activities/index.d.ts +2 -2
- package/build/services/activities/index.js +2 -2
- package/build/services/activities/interrupt.d.ts +16 -0
- package/build/services/activities/interrupt.js +129 -0
- package/build/services/activities/signal.js +9 -2
- package/build/services/activities/trigger.d.ts +4 -0
- package/build/services/activities/trigger.js +14 -4
- package/build/services/activities/worker.js +10 -2
- package/build/services/collator/index.d.ts +4 -0
- package/build/services/collator/index.js +8 -0
- package/build/services/compiler/deployer.js +1 -3
- package/build/services/connector/index.js +2 -3
- package/build/services/durable/client.js +7 -3
- package/build/services/durable/factory.js +65 -284
- package/build/services/durable/handle.d.ts +37 -0
- package/build/services/durable/handle.js +52 -9
- package/build/services/durable/meshos.js +2 -2
- package/build/services/durable/worker.js +9 -2
- package/build/services/durable/workflow.d.ts +24 -0
- package/build/services/durable/workflow.js +56 -1
- package/build/services/engine/index.d.ts +14 -6
- package/build/services/engine/index.js +52 -27
- package/build/services/hotmesh/index.d.ts +3 -1
- package/build/services/hotmesh/index.js +11 -3
- package/build/services/quorum/index.d.ts +1 -0
- package/build/services/quorum/index.js +10 -0
- package/build/services/signaler/stream.js +25 -29
- package/build/services/store/clients/ioredis.js +1 -0
- package/build/services/store/index.d.ts +40 -4
- package/build/services/store/index.js +114 -9
- package/build/services/task/index.d.ts +5 -4
- package/build/services/task/index.js +12 -14
- package/build/types/activity.d.ts +35 -5
- package/build/types/durable.d.ts +4 -0
- package/build/types/index.d.ts +1 -1
- package/build/types/job.d.ts +18 -1
- package/build/types/quorum.d.ts +11 -7
- package/build/types/stream.d.ts +4 -1
- package/build/types/stream.js +2 -0
- package/modules/enums.ts +32 -0
- package/modules/errors.ts +24 -9
- package/modules/key.ts +4 -1
- package/modules/utils.ts +5 -0
- package/package.json +3 -1
- package/services/activities/activity.ts +34 -8
- package/services/activities/await.ts +11 -4
- package/services/activities/cycle.ts +10 -3
- package/services/activities/hook.ts +8 -3
- package/services/activities/index.ts +2 -2
- package/services/activities/interrupt.ts +159 -0
- package/services/activities/signal.ts +9 -3
- package/services/activities/trigger.ts +21 -5
- package/services/activities/worker.ts +10 -3
- package/services/collator/index.ts +10 -1
- package/services/compiler/deployer.ts +1 -3
- package/services/connector/index.ts +3 -5
- package/services/durable/client.ts +8 -4
- package/services/durable/factory.ts +65 -284
- package/services/durable/handle.ts +55 -9
- package/services/durable/meshos.ts +2 -3
- package/services/durable/worker.ts +9 -2
- package/services/durable/workflow.ts +66 -2
- package/services/engine/index.ts +74 -26
- package/services/hotmesh/index.ts +14 -4
- package/services/quorum/index.ts +9 -0
- package/services/signaler/stream.ts +27 -24
- package/services/store/clients/ioredis.ts +1 -0
- package/services/store/index.ts +119 -11
- package/services/task/index.ts +18 -18
- package/types/activity.ts +38 -8
- package/types/durable.ts +8 -4
- package/types/index.ts +1 -1
- package/types/job.ts +30 -1
- package/types/quorum.ts +13 -8
- package/types/stream.ts +3 -0
- package/build/services/activities/iterate.d.ts +0 -9
- package/build/services/activities/iterate.js +0 -13
- package/services/activities/iterate.ts +0 -26
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { nanoid } from 'nanoid';
|
|
2
1
|
import { DuplicateJobError } from '../../modules/errors';
|
|
3
|
-
import { formatISODate, getTimeSeries } from '../../modules/utils';
|
|
2
|
+
import { formatISODate, getTimeSeries, guid } from '../../modules/utils';
|
|
4
3
|
import { Activity } from './activity';
|
|
5
4
|
import { CollatorService } from '../collator';
|
|
6
5
|
import { EngineService } from '../engine';
|
|
@@ -47,6 +46,7 @@ class Trigger extends Activity {
|
|
|
47
46
|
const multi = this.store.getMulti();
|
|
48
47
|
await this.setState(multi);
|
|
49
48
|
await this.setStats(multi);
|
|
49
|
+
await this.setDependency(multi);
|
|
50
50
|
await multi.exec();
|
|
51
51
|
|
|
52
52
|
telemetry.mapActivityAttributes();
|
|
@@ -68,8 +68,8 @@ class Trigger extends Activity {
|
|
|
68
68
|
telemetry.setActivityError(error.message);
|
|
69
69
|
throw error;
|
|
70
70
|
} finally {
|
|
71
|
-
telemetry
|
|
72
|
-
telemetry
|
|
71
|
+
telemetry?.endJobSpan();
|
|
72
|
+
telemetry?.endActivitySpan();
|
|
73
73
|
this.logger.debug('trigger-process-end', { subscribes: this.config.subscribes, jid: this.context.metadata.jid });
|
|
74
74
|
}
|
|
75
75
|
}
|
|
@@ -161,7 +161,7 @@ class Trigger extends Activity {
|
|
|
161
161
|
|
|
162
162
|
resolveJobId(context: Partial<JobState>): string {
|
|
163
163
|
const jobId = this.config.stats?.id;
|
|
164
|
-
return jobId ? Pipe.resolve(jobId, context) :
|
|
164
|
+
return jobId ? Pipe.resolve(jobId, context) : guid();
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
resolveJobKey(context: Partial<JobState>): string {
|
|
@@ -176,6 +176,22 @@ class Trigger extends Activity {
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
/**
|
|
180
|
+
* Registers this job as a dependent of the parent job
|
|
181
|
+
*/
|
|
182
|
+
async setDependency(multi?: RedisMulti): Promise<void> {
|
|
183
|
+
const depKey = this.config.stats?.parent;
|
|
184
|
+
const resolvedDepKey = depKey ? Pipe.resolve(depKey, this.context) : '';
|
|
185
|
+
if (resolvedDepKey) {
|
|
186
|
+
await this.store.setDependency(
|
|
187
|
+
resolvedDepKey,
|
|
188
|
+
this.context.metadata.tpc,
|
|
189
|
+
this.context.metadata.jid,
|
|
190
|
+
multi,
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
179
195
|
async setStats(multi?: RedisMulti): Promise<void> {
|
|
180
196
|
const md = this.context.metadata;
|
|
181
197
|
if (md.key && this.config.stats?.measures) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GetStateError } from '../../modules/errors';
|
|
1
|
+
import { GetStateError, InactiveJobError } from '../../modules/errors';
|
|
2
2
|
import { Activity } from './activity';
|
|
3
3
|
import { CollatorService } from '../collator';
|
|
4
4
|
import { EngineService } from '../engine';
|
|
@@ -12,6 +12,7 @@ import { MultiResponseFlags, RedisMulti } from '../../types/redis';
|
|
|
12
12
|
import { StreamData} from '../../types/stream';
|
|
13
13
|
import { TelemetryService } from '../telemetry';
|
|
14
14
|
import { Pipe } from '../pipe';
|
|
15
|
+
import { guid } from '../../modules/utils';
|
|
15
16
|
|
|
16
17
|
class Worker extends Activity {
|
|
17
18
|
config: WorkerActivity;
|
|
@@ -35,6 +36,7 @@ class Worker extends Activity {
|
|
|
35
36
|
this.setLeg(1);
|
|
36
37
|
await CollatorService.notarizeEntry(this);
|
|
37
38
|
await this.getState();
|
|
39
|
+
CollatorService.assertJobActive(this.context.metadata.js, this.context.metadata.jid, this.metadata.aid);
|
|
38
40
|
telemetry = new TelemetryService(this.engine.appId, this.config, this.metadata, this.context);
|
|
39
41
|
telemetry.startActivitySpan(this.leg);
|
|
40
42
|
this.mapInputData();
|
|
@@ -58,15 +60,19 @@ class Worker extends Activity {
|
|
|
58
60
|
|
|
59
61
|
return this.context.metadata.aid;
|
|
60
62
|
} catch (error) {
|
|
61
|
-
if (error instanceof
|
|
63
|
+
if (error instanceof InactiveJobError) {
|
|
64
|
+
this.logger.error('await-inactive-job-error', { error });
|
|
65
|
+
return;
|
|
66
|
+
} else if (error instanceof GetStateError) {
|
|
62
67
|
this.logger.error('worker-get-state-error', { error });
|
|
68
|
+
return;
|
|
63
69
|
} else {
|
|
64
70
|
this.logger.error('worker-process-error', { error });
|
|
65
71
|
}
|
|
66
72
|
telemetry.setActivityError(error.message);
|
|
67
73
|
throw error;
|
|
68
74
|
} finally {
|
|
69
|
-
telemetry
|
|
75
|
+
telemetry?.endActivitySpan();
|
|
70
76
|
this.logger.debug('worker-process-end', { jid: this.context.metadata.jid, aid: this.metadata.aid });
|
|
71
77
|
}
|
|
72
78
|
}
|
|
@@ -75,6 +81,7 @@ class Worker extends Activity {
|
|
|
75
81
|
const topic = Pipe.resolve(this.config.subtype, this.context);
|
|
76
82
|
const streamData: StreamData = {
|
|
77
83
|
metadata: {
|
|
84
|
+
guid: guid(),
|
|
78
85
|
jid: this.context.metadata.jid,
|
|
79
86
|
dad: this.metadata.dad,
|
|
80
87
|
aid: this.metadata.aid,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CollationError } from '../../modules/errors';
|
|
1
|
+
import { CollationError, InactiveJobError } from '../../modules/errors';
|
|
2
2
|
import { RedisMulti } from '../../types/redis';
|
|
3
3
|
import { CollationFaultType, CollationStage } from '../../types/collator';
|
|
4
4
|
import { ActivityDuplex } from '../../types/activity';
|
|
@@ -11,6 +11,15 @@ class CollatorService {
|
|
|
11
11
|
//max int digit count that supports `hincrby`
|
|
12
12
|
static targetLength = 15;
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Upon re/entry, verify that the job status is active
|
|
16
|
+
*/
|
|
17
|
+
static assertJobActive(status: number, jobId: string, activityId: string): void {
|
|
18
|
+
if (status <= 0) {
|
|
19
|
+
throw new InactiveJobError(jobId, status, activityId);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
14
23
|
/**
|
|
15
24
|
* returns the dimensional address (dad) for the target; due
|
|
16
25
|
* to the nature of the notary system, the dad for leg 2 entry
|
|
@@ -143,9 +143,7 @@ class Deployer {
|
|
|
143
143
|
if (graph.publishes) {
|
|
144
144
|
activities[activityKey].publishes = graph.publishes;
|
|
145
145
|
}
|
|
146
|
-
|
|
147
|
-
activities[activityKey].expire = graph.expire;
|
|
148
|
-
}
|
|
146
|
+
activities[activityKey].expire = graph.expire ?? undefined;
|
|
149
147
|
}
|
|
150
148
|
}
|
|
151
149
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { identifyRedisTypeFromClass } from '../../modules/utils';
|
|
1
|
+
import { guid, identifyRedisTypeFromClass } from '../../modules/utils';
|
|
4
2
|
import { RedisConnection as IORedisConnection } from '../connector/clients/ioredis';
|
|
5
3
|
import { RedisConnection } from '../connector/clients/redis';
|
|
6
4
|
import {
|
|
@@ -23,14 +21,14 @@ export class ConnectorService {
|
|
|
23
21
|
if (identifyRedisTypeFromClass(Redis) === 'redis') {
|
|
24
22
|
for (let i = 1; i <= 3; i++) {
|
|
25
23
|
instances.push(RedisConnection.connect(
|
|
26
|
-
|
|
24
|
+
guid(),
|
|
27
25
|
Redis as RedisClassType,
|
|
28
26
|
options as RedisClientOptions));
|
|
29
27
|
}
|
|
30
28
|
} else {
|
|
31
29
|
for (let i = 1; i <= 3; i++) {
|
|
32
30
|
instances.push(IORedisConnection.connect(
|
|
33
|
-
|
|
31
|
+
guid(),
|
|
34
32
|
Redis as IORedisClassType,
|
|
35
33
|
options as IORedisClientOptions));
|
|
36
34
|
}
|
|
@@ -11,6 +11,7 @@ import { JobState } from '../../types/job';
|
|
|
11
11
|
import { KeyService, KeyType } from '../../modules/key';
|
|
12
12
|
import { Search } from './search';
|
|
13
13
|
import { StreamStatus } from '../../types';
|
|
14
|
+
import { DURABLE_EXPIRE_SECONDS } from '../../modules/enums';
|
|
14
15
|
|
|
15
16
|
export class ClientService {
|
|
16
17
|
|
|
@@ -96,12 +97,15 @@ export class ClientService {
|
|
|
96
97
|
const workflowName = options.entity ?? options.workflowName;
|
|
97
98
|
const trc = options.workflowTrace;
|
|
98
99
|
const spn = options.workflowSpan;
|
|
99
|
-
//
|
|
100
|
+
//NOTE: HotMesh 'workflowTopic' is a created by concatenating
|
|
101
|
+
// the taskQueue and workflowName used by the Durable module
|
|
100
102
|
const workflowTopic = `${taskQueueName}-${workflowName}`;
|
|
101
103
|
const hotMeshClient = await this.getHotMeshClient(workflowTopic, options.namespace);
|
|
102
|
-
this.configureSearchIndex(hotMeshClient, options.search)
|
|
104
|
+
this.configureSearchIndex(hotMeshClient, options.search);
|
|
103
105
|
const payload = {
|
|
104
106
|
arguments: [...options.args],
|
|
107
|
+
originJobId: options.originJobId,
|
|
108
|
+
expire: options.expire ?? DURABLE_EXPIRE_SECONDS,
|
|
105
109
|
parentWorkflowId: options.parentWorkflowId,
|
|
106
110
|
workflowId: options.workflowId || HotMesh.guid(),
|
|
107
111
|
workflowTopic: workflowTopic,
|
|
@@ -113,12 +117,12 @@ export class ClientService {
|
|
|
113
117
|
payload,
|
|
114
118
|
context as JobState
|
|
115
119
|
);
|
|
116
|
-
// Seed search data
|
|
120
|
+
// Seed search data
|
|
117
121
|
if (jobId && options.search?.data) {
|
|
118
122
|
const searchSessionId = `-search-0`;
|
|
119
123
|
const search = new Search(jobId, hotMeshClient, searchSessionId);
|
|
120
124
|
const entries = Object.entries(options.search.data).flat();
|
|
121
|
-
search.set(...entries);
|
|
125
|
+
await search.set(...entries);
|
|
122
126
|
}
|
|
123
127
|
return new WorkflowHandleService(hotMeshClient, workflowTopic, jobId);
|
|
124
128
|
},
|