@hotmeshio/hotmesh 0.0.34 → 0.0.35
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/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/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
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# HotMesh
|
|
2
2
|

|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
HotMesh elevates Redis from an in-memory data cache to a distributed orchestration engine.
|
|
5
5
|
|
|
6
|
-
*Write functions in your own preferred style, and let Redis govern their execution.*
|
|
6
|
+
*Write functions in your own preferred style, and let Redis govern their execution, reliably and durably.*
|
|
7
7
|
|
|
8
8
|
## Install
|
|
9
9
|
[](https://badge.fury.io/js/%40hotmeshio%2Fhotmesh)
|
|
@@ -11,7 +11,16 @@ Elevate Redis from an in-memory data cache, and turn your unpredictable function
|
|
|
11
11
|
```sh
|
|
12
12
|
npm install @hotmeshio/hotmesh
|
|
13
13
|
```
|
|
14
|
+
|
|
15
|
+
## Understanding HotMesh
|
|
16
|
+
HotMesh inverts the relationship to Redis: those functions that once used Redis as a cache, are instead *cached and governed* by Redis. Consider the following. It's a typical microservices network, with a tangled mess of services and functions. There's important business logic in there (functions *A*, *B* and *C* are critical!), but they're hard to find and access.
|
|
17
|
+
|
|
18
|
+
<img src="https://github.com/hotmeshio/sdk-typescript/blob/main/docs/img/operational_data_layer.png" alt="A Tangled Microservices Network with 3 functions buried within" style="max-width:100%;width:600px;">
|
|
19
|
+
|
|
20
|
+
HotMesh creates an *ad hoc*, Redis-backed network of functions and organizes them into a unified service mesh. *Any service with access to Redis can join in the network, bypassing the legacy clutter.*
|
|
21
|
+
|
|
14
22
|
## Design
|
|
23
|
+
The simplest way to get started is to use the `Durable` module. It's organized using principles similar to Temporal. If you're familiar with their SDK, the setup is similar.
|
|
15
24
|
|
|
16
25
|
1. Start by defining **activities**. Activities can be written in any style, using any framework, and can even be legacy functions you've already written. The only requirement is that they return a Promise. *Note how the `saludar` example throws an error 50% of the time. It doesn't matter how unpredictable your functions are, HotMesh will retry as necessary until they succeed.*
|
|
17
26
|
```javascript
|
|
@@ -47,9 +56,8 @@ npm install @hotmeshio/hotmesh
|
|
|
47
56
|
3. Instance a HotMesh **client** to invoke the workflow.
|
|
48
57
|
```javascript
|
|
49
58
|
//client.ts
|
|
50
|
-
import { Durable } from '@hotmeshio/hotmesh';
|
|
59
|
+
import { Durable, HotMesh } from '@hotmeshio/hotmesh';
|
|
51
60
|
import Redis from 'ioredis'; //OR `import * as Redis from 'redis';`
|
|
52
|
-
import { nanoid } from 'nanoid';
|
|
53
61
|
|
|
54
62
|
async function run(): Promise<string> {
|
|
55
63
|
const client = new Durable.Client({
|
|
@@ -61,9 +69,9 @@ npm install @hotmeshio/hotmesh
|
|
|
61
69
|
|
|
62
70
|
const handle = await client.workflow.start({
|
|
63
71
|
args: ['HotMesh', 'es'],
|
|
64
|
-
taskQueue: '
|
|
72
|
+
taskQueue: 'default',
|
|
65
73
|
workflowName: 'example',
|
|
66
|
-
workflowId:
|
|
74
|
+
workflowId: HotMesh.guid()
|
|
67
75
|
});
|
|
68
76
|
|
|
69
77
|
return await handle.result();
|
|
@@ -83,7 +91,7 @@ npm install @hotmeshio/hotmesh
|
|
|
83
91
|
class: Redis,
|
|
84
92
|
options: { host: 'localhost', port: 6379 },
|
|
85
93
|
},
|
|
86
|
-
taskQueue: '
|
|
94
|
+
taskQueue: 'default',
|
|
87
95
|
workflow: workflows.example,
|
|
88
96
|
});
|
|
89
97
|
|
|
@@ -92,7 +100,7 @@ npm install @hotmeshio/hotmesh
|
|
|
92
100
|
```
|
|
93
101
|
|
|
94
102
|
### Workflow Extensions
|
|
95
|
-
Redis governance delivers more than just reliability. Externalizing state fundamentally changes the execution profile for your functions, allowing you to design long-running, durable workflows. The `Durable
|
|
103
|
+
Redis governance delivers more than just reliability. Externalizing state fundamentally changes the execution profile for your functions, allowing you to design long-running, durable workflows. The `Durable` base class (shown in the examples above) provides additional methods for solving the most common state management challenges.
|
|
96
104
|
|
|
97
105
|
- `waitForSignal` Pause your function and wait for external event(s) before continuing. The *waitForSignal* method will collate and cache the signals and only awaken your function once all signals have arrived.
|
|
98
106
|
```javascript
|
|
@@ -134,6 +142,10 @@ Redis governance delivers more than just reliability. Externalizing state fundam
|
|
|
134
142
|
args: [{ id, user_id, etc }],
|
|
135
143
|
});
|
|
136
144
|
```
|
|
145
|
+
- `getContext` Get the current workflow context (workflowId, etc).
|
|
146
|
+
```javascript
|
|
147
|
+
const context = await Durable.workflow.getContext();
|
|
148
|
+
```
|
|
137
149
|
- `search` Instance a search session
|
|
138
150
|
```javascript
|
|
139
151
|
const search = await Durable.workflow.search();
|
|
@@ -273,31 +285,31 @@ const hotMesh = await HotMesh.init({
|
|
|
273
285
|
```
|
|
274
286
|
|
|
275
287
|
### Observability
|
|
276
|
-
Workflows and activities are run according to the rules you define, offering [Graph-Oriented](https://github.com/hotmeshio/sdk-typescript/
|
|
288
|
+
Workflows and activities are run according to the rules you define, offering [Graph-Oriented](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/system_lifecycle.md#telemetry) telemetry insights into your legacy function executions.
|
|
277
289
|
|
|
278
290
|
## FAQ
|
|
279
|
-
Refer to the [FAQ](https://github.com/hotmeshio/sdk-typescript/
|
|
291
|
+
Refer to the [FAQ](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/faq.md) for terminology, definitions, and an exploration of how HotMesh facilitates orchestration use cases.
|
|
280
292
|
|
|
281
293
|
## Quick Start
|
|
282
|
-
Refer to the [Quick Start](https://github.com/hotmeshio/sdk-typescript/
|
|
294
|
+
Refer to the [Quick Start](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/quickstart.md) for sample flows you can easily copy, paste, and modify to get started.
|
|
283
295
|
|
|
284
296
|
## Developer Guide
|
|
285
|
-
For more details on the complete development process, including information about schemas, APIs, and deployment, consult the [Developer Guide](https://github.com/hotmeshio/sdk-typescript/
|
|
297
|
+
For more details on the complete development process, including information about schemas, APIs, and deployment, consult the [Developer Guide](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/developer_guide.md).
|
|
286
298
|
|
|
287
299
|
## Model Driven Development
|
|
288
|
-
[Model Driven Development](https://github.com/hotmeshio/sdk-typescript/
|
|
300
|
+
[Model Driven Development](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/model_driven_development.md) is an established strategy for managing process-oriented tasks. Check out this guide to understand its foundational principles.
|
|
289
301
|
|
|
290
302
|
## Data Mapping
|
|
291
|
-
Exchanging data between activities is central to HotMesh. For detailed information on supported functions and the functional mapping syntax (@pipes), see the [Data Mapping Overview](https://github.com/hotmeshio/sdk-typescript/
|
|
303
|
+
Exchanging data between activities is central to HotMesh. For detailed information on supported functions and the functional mapping syntax (@pipes), see the [Data Mapping Overview](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/data_mapping.md).
|
|
292
304
|
|
|
293
305
|
## Composition
|
|
294
|
-
While the simplest graphs are linear, detailing a consistent sequence of non-cyclical activities, graphs can be layered to represent intricate business scenarios. Some can even be designed to accommodate long-lasting workflows that span months. For more details, check out the [Composable Workflow Guide](https://github.com/hotmeshio/sdk-typescript/
|
|
306
|
+
While the simplest graphs are linear, detailing a consistent sequence of non-cyclical activities, graphs can be layered to represent intricate business scenarios. Some can even be designed to accommodate long-lasting workflows that span months. For more details, check out the [Composable Workflow Guide](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/composable_workflow.md).
|
|
295
307
|
|
|
296
308
|
## Distributed Orchestration
|
|
297
|
-
HotMesh is a distributed orchestration engine. Refer to the [Distributed Orchestration Guide](https://github.com/hotmeshio/sdk-typescript/
|
|
309
|
+
HotMesh is a distributed orchestration engine. Refer to the [Distributed Orchestration Guide](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/distributed_orchestration.md) for a detailed breakdown of the approach.
|
|
298
310
|
|
|
299
311
|
## System Lifecycle
|
|
300
|
-
Gain insight into HotMesh's monitoring, exception handling, and alarm configurations via the [System Lifecycle Guide](https://github.com/hotmeshio/sdk-typescript/
|
|
312
|
+
Gain insight into HotMesh's monitoring, exception handling, and alarm configurations via the [System Lifecycle Guide](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/system_lifecycle.md).
|
|
301
313
|
|
|
302
314
|
## Alpha Release
|
|
303
|
-
So what exacty is an [alpha release](https://github.com/hotmeshio/sdk-typescript/
|
|
315
|
+
So what exacty is an [alpha release](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/alpha.md)?
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare const STATUS_CODE_SUCCESS = 200;
|
|
2
|
+
export declare const STATUS_CODE_PENDING = 202;
|
|
3
|
+
export declare const STATUS_CODE_TIMEOUT = 504;
|
|
4
|
+
export declare const STATUS_CODE_INTERRUPT = 410;
|
|
5
|
+
export declare const OTT_WAIT_TIME = 1000;
|
|
6
|
+
export declare const MAX_RETRIES = 3;
|
|
7
|
+
export declare const MAX_TIMEOUT_MS = 60000;
|
|
8
|
+
export declare const GRADUATED_INTERVAL_MS = 5000;
|
|
9
|
+
export declare const BLOCK_DURATION = 15000;
|
|
10
|
+
export declare const TEST_BLOCK_DURATION = 1000;
|
|
11
|
+
export declare const BLOCK_TIME_MS: number;
|
|
12
|
+
export declare const XCLAIM_DELAY_MS: number;
|
|
13
|
+
export declare const XCLAIM_COUNT = 3;
|
|
14
|
+
export declare const XPENDING_COUNT = 10;
|
|
15
|
+
export declare const STATUS_CODE_UNACKED = 999;
|
|
16
|
+
export declare const STATUS_CODE_UNKNOWN = 500;
|
|
17
|
+
export declare const STATUS_MESSAGE_UNKNOWN = "unknown";
|
|
18
|
+
export declare const EXPIRE_DURATION = 15;
|
|
19
|
+
export declare const BASE_FIDELITY_SECONDS = 15;
|
|
20
|
+
export declare const TEST_FIDELITY_SECONDS = 5;
|
|
21
|
+
export declare const FIDELITY_SECONDS: number;
|
|
22
|
+
export declare const DURABLE_EXPIRE_SECONDS = 1;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DURABLE_EXPIRE_SECONDS = exports.FIDELITY_SECONDS = exports.TEST_FIDELITY_SECONDS = exports.BASE_FIDELITY_SECONDS = exports.EXPIRE_DURATION = exports.STATUS_MESSAGE_UNKNOWN = exports.STATUS_CODE_UNKNOWN = exports.STATUS_CODE_UNACKED = exports.XPENDING_COUNT = exports.XCLAIM_COUNT = exports.XCLAIM_DELAY_MS = exports.BLOCK_TIME_MS = exports.TEST_BLOCK_DURATION = exports.BLOCK_DURATION = exports.GRADUATED_INTERVAL_MS = exports.MAX_TIMEOUT_MS = exports.MAX_RETRIES = exports.OTT_WAIT_TIME = exports.STATUS_CODE_INTERRUPT = exports.STATUS_CODE_TIMEOUT = exports.STATUS_CODE_PENDING = exports.STATUS_CODE_SUCCESS = void 0;
|
|
4
|
+
// Engine Constants
|
|
5
|
+
exports.STATUS_CODE_SUCCESS = 200;
|
|
6
|
+
exports.STATUS_CODE_PENDING = 202;
|
|
7
|
+
exports.STATUS_CODE_TIMEOUT = 504;
|
|
8
|
+
exports.STATUS_CODE_INTERRUPT = 410;
|
|
9
|
+
exports.OTT_WAIT_TIME = 1000;
|
|
10
|
+
// Stream Constants
|
|
11
|
+
exports.MAX_RETRIES = 3; //local retry; 10, 100, 1000ms
|
|
12
|
+
exports.MAX_TIMEOUT_MS = 60000;
|
|
13
|
+
exports.GRADUATED_INTERVAL_MS = 5000;
|
|
14
|
+
exports.BLOCK_DURATION = 15000; //Set to `15` so SIGINT/SIGTERM can interrupt; set to `0` to BLOCK indefinitely
|
|
15
|
+
exports.TEST_BLOCK_DURATION = 1000; //Set to `1000` so tests can interrupt quickly
|
|
16
|
+
exports.BLOCK_TIME_MS = process.env.NODE_ENV === 'test' ? exports.TEST_BLOCK_DURATION : exports.BLOCK_DURATION;
|
|
17
|
+
exports.XCLAIM_DELAY_MS = 1000 * 60; //max time a message can be unacked before it is claimed by another
|
|
18
|
+
exports.XCLAIM_COUNT = 3; //max number of times a message can be claimed by another before it is dead-lettered
|
|
19
|
+
exports.XPENDING_COUNT = 10;
|
|
20
|
+
exports.STATUS_CODE_UNACKED = 999;
|
|
21
|
+
exports.STATUS_CODE_UNKNOWN = 500;
|
|
22
|
+
exports.STATUS_MESSAGE_UNKNOWN = 'unknown';
|
|
23
|
+
// HotMesh Constants
|
|
24
|
+
exports.EXPIRE_DURATION = 15; // default expire in seconds; once job state semaphore reaches '0', this is applied to set Redis to expire the job HASH
|
|
25
|
+
exports.BASE_FIDELITY_SECONDS = 15; // granularity resolution window size
|
|
26
|
+
exports.TEST_FIDELITY_SECONDS = 5;
|
|
27
|
+
exports.FIDELITY_SECONDS = process.env.NODE_ENV === 'test' ? exports.TEST_FIDELITY_SECONDS : exports.BASE_FIDELITY_SECONDS;
|
|
28
|
+
// DURABLE CONSTANTS
|
|
29
|
+
exports.DURABLE_EXPIRE_SECONDS = 1;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { ActivityDuplex } from "../types/activity";
|
|
2
2
|
import { CollationFaultType, CollationStage } from "../types/collator";
|
|
3
3
|
declare class GetStateError extends Error {
|
|
4
|
-
|
|
4
|
+
jobId: string;
|
|
5
|
+
code: 404;
|
|
6
|
+
constructor(jobId: string);
|
|
5
7
|
}
|
|
6
8
|
declare class SetStateError extends Error {
|
|
7
9
|
constructor();
|
|
@@ -60,6 +62,12 @@ declare class RegisterTimeoutError extends Error {
|
|
|
60
62
|
declare class DuplicateJobError extends Error {
|
|
61
63
|
constructor(jobId: string);
|
|
62
64
|
}
|
|
65
|
+
declare class InactiveJobError extends Error {
|
|
66
|
+
jobId: string;
|
|
67
|
+
activityId: string;
|
|
68
|
+
status: number;
|
|
69
|
+
constructor(jobId: string, status: number, activityId: string);
|
|
70
|
+
}
|
|
63
71
|
declare class ExecActivityError extends Error {
|
|
64
72
|
constructor();
|
|
65
73
|
}
|
|
@@ -70,4 +78,4 @@ declare class CollationError extends Error {
|
|
|
70
78
|
fault: CollationFaultType;
|
|
71
79
|
constructor(status: number, leg: ActivityDuplex, stage: CollationStage, fault?: CollationFaultType);
|
|
72
80
|
}
|
|
73
|
-
export { CollationError,
|
|
81
|
+
export { CollationError, DurableFatalError, DurableIncompleteSignalError, DurableMaxedError, DurableRetryError, DurableSleepError, DurableSleepForError, DurableTimeoutError, DurableWaitForSignalError, DuplicateJobError, ExecActivityError, GetStateError, InactiveJobError, MapDataError, RegisterTimeoutError, SetStateError, };
|
package/build/modules/errors.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.SetStateError = exports.RegisterTimeoutError = exports.MapDataError = exports.InactiveJobError = exports.GetStateError = exports.ExecActivityError = exports.DuplicateJobError = exports.DurableWaitForSignalError = exports.DurableTimeoutError = exports.DurableSleepForError = exports.DurableSleepError = exports.DurableRetryError = exports.DurableMaxedError = exports.DurableIncompleteSignalError = exports.DurableFatalError = exports.CollationError = void 0;
|
|
4
4
|
class GetStateError extends Error {
|
|
5
|
-
constructor() {
|
|
6
|
-
super(
|
|
5
|
+
constructor(jobId) {
|
|
6
|
+
super(`${jobId} Not Found`);
|
|
7
|
+
this.jobId = jobId;
|
|
7
8
|
}
|
|
8
9
|
}
|
|
9
10
|
exports.GetStateError = GetStateError;
|
|
@@ -99,6 +100,16 @@ class DuplicateJobError extends Error {
|
|
|
99
100
|
}
|
|
100
101
|
}
|
|
101
102
|
exports.DuplicateJobError = DuplicateJobError;
|
|
103
|
+
class InactiveJobError extends Error {
|
|
104
|
+
constructor(jobId, status, activityId) {
|
|
105
|
+
super("Inactive job");
|
|
106
|
+
this.jobId = jobId;
|
|
107
|
+
this.activityId = activityId;
|
|
108
|
+
this.message = `Inactive job: ${jobId}`;
|
|
109
|
+
this.status = status;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.InactiveJobError = InactiveJobError;
|
|
102
113
|
class ExecActivityError extends Error {
|
|
103
114
|
constructor() {
|
|
104
115
|
super("Error occurred while executing activity");
|
package/build/modules/key.d.ts
CHANGED
|
@@ -30,21 +30,22 @@ declare enum KeyType {
|
|
|
30
30
|
APP = 0,
|
|
31
31
|
ENGINE_ID = 1,
|
|
32
32
|
HOOKS = 2,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
33
|
+
JOB_DEPENDENTS = 3,
|
|
34
|
+
JOB_STATE = 4,
|
|
35
|
+
JOB_STATS_GENERAL = 5,
|
|
36
|
+
JOB_STATS_MEDIAN = 6,
|
|
37
|
+
JOB_STATS_INDEX = 7,
|
|
38
|
+
HOTMESH = 8,
|
|
39
|
+
QUORUM = 9,
|
|
40
|
+
SCHEMAS = 10,
|
|
41
|
+
SIGNALS = 11,
|
|
42
|
+
STREAMS = 12,
|
|
43
|
+
SUBSCRIPTIONS = 13,
|
|
44
|
+
SUBSCRIPTION_PATTERNS = 14,
|
|
45
|
+
SYMKEYS = 15,
|
|
46
|
+
SYMVALS = 16,
|
|
47
|
+
TIME_RANGE = 17,
|
|
48
|
+
WORK_ITEMS = 18
|
|
48
49
|
}
|
|
49
50
|
type KeyStoreParams = {
|
|
50
51
|
appId?: string;
|
package/build/modules/key.js
CHANGED
|
@@ -37,21 +37,22 @@ var KeyType;
|
|
|
37
37
|
KeyType[KeyType["APP"] = 0] = "APP";
|
|
38
38
|
KeyType[KeyType["ENGINE_ID"] = 1] = "ENGINE_ID";
|
|
39
39
|
KeyType[KeyType["HOOKS"] = 2] = "HOOKS";
|
|
40
|
-
KeyType[KeyType["
|
|
41
|
-
KeyType[KeyType["
|
|
42
|
-
KeyType[KeyType["
|
|
43
|
-
KeyType[KeyType["
|
|
44
|
-
KeyType[KeyType["
|
|
45
|
-
KeyType[KeyType["
|
|
46
|
-
KeyType[KeyType["
|
|
47
|
-
KeyType[KeyType["
|
|
48
|
-
KeyType[KeyType["
|
|
49
|
-
KeyType[KeyType["
|
|
50
|
-
KeyType[KeyType["
|
|
51
|
-
KeyType[KeyType["
|
|
52
|
-
KeyType[KeyType["
|
|
53
|
-
KeyType[KeyType["
|
|
54
|
-
KeyType[KeyType["
|
|
40
|
+
KeyType[KeyType["JOB_DEPENDENTS"] = 3] = "JOB_DEPENDENTS";
|
|
41
|
+
KeyType[KeyType["JOB_STATE"] = 4] = "JOB_STATE";
|
|
42
|
+
KeyType[KeyType["JOB_STATS_GENERAL"] = 5] = "JOB_STATS_GENERAL";
|
|
43
|
+
KeyType[KeyType["JOB_STATS_MEDIAN"] = 6] = "JOB_STATS_MEDIAN";
|
|
44
|
+
KeyType[KeyType["JOB_STATS_INDEX"] = 7] = "JOB_STATS_INDEX";
|
|
45
|
+
KeyType[KeyType["HOTMESH"] = 8] = "HOTMESH";
|
|
46
|
+
KeyType[KeyType["QUORUM"] = 9] = "QUORUM";
|
|
47
|
+
KeyType[KeyType["SCHEMAS"] = 10] = "SCHEMAS";
|
|
48
|
+
KeyType[KeyType["SIGNALS"] = 11] = "SIGNALS";
|
|
49
|
+
KeyType[KeyType["STREAMS"] = 12] = "STREAMS";
|
|
50
|
+
KeyType[KeyType["SUBSCRIPTIONS"] = 13] = "SUBSCRIPTIONS";
|
|
51
|
+
KeyType[KeyType["SUBSCRIPTION_PATTERNS"] = 14] = "SUBSCRIPTION_PATTERNS";
|
|
52
|
+
KeyType[KeyType["SYMKEYS"] = 15] = "SYMKEYS";
|
|
53
|
+
KeyType[KeyType["SYMVALS"] = 16] = "SYMVALS";
|
|
54
|
+
KeyType[KeyType["TIME_RANGE"] = 17] = "TIME_RANGE";
|
|
55
|
+
KeyType[KeyType["WORK_ITEMS"] = 18] = "WORK_ITEMS";
|
|
55
56
|
})(KeyType || (KeyType = {}));
|
|
56
57
|
exports.KeyType = KeyType;
|
|
57
58
|
class KeyService {
|
|
@@ -82,6 +83,8 @@ class KeyService {
|
|
|
82
83
|
return `${namespace}:${params.appId}:q:${params.engineId || ''}`;
|
|
83
84
|
case KeyType.JOB_STATE:
|
|
84
85
|
return `${namespace}:${params.appId}:j:${params.jobId}`;
|
|
86
|
+
case KeyType.JOB_DEPENDENTS:
|
|
87
|
+
return `${namespace}:${params.appId}:d:${params.jobId}`;
|
|
85
88
|
case KeyType.JOB_STATS_GENERAL:
|
|
86
89
|
return `${namespace}:${params.appId}:s:${params.jobKey}:${params.dateTime}`;
|
|
87
90
|
case KeyType.JOB_STATS_MEDIAN:
|
package/build/modules/utils.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { RedisClient, RedisMulti } from "../types/redis";
|
|
|
5
5
|
import { StringAnyType } from "../types/serializer";
|
|
6
6
|
import { StreamCode, StreamStatus } from "../types/stream";
|
|
7
7
|
export declare function sleepFor(ms: number): Promise<unknown>;
|
|
8
|
+
export declare function guid(): string;
|
|
8
9
|
export declare function deterministicRandom(seed: number): number;
|
|
9
10
|
export declare function identifyRedisType(redisInstance: any): 'redis' | 'ioredis' | null;
|
|
10
11
|
export declare const polyfill: {
|
package/build/modules/utils.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.restoreHierarchy = exports.getValueByPath = exports.getIndexedHash = exports.getSymVal = exports.getSymKey = exports.formatISODate = exports.getTimeSeries = exports.getSubscriptionTopic = exports.findSubscriptionForTrigger = exports.findTopKey = exports.XSleepFor = exports.matchesStatus = exports.matchesStatusCode = exports.identifyRedisTypeFromClass = exports.polyfill = exports.identifyRedisType = exports.deterministicRandom = exports.sleepFor = void 0;
|
|
3
|
+
exports.restoreHierarchy = exports.getValueByPath = exports.getIndexedHash = exports.getSymVal = exports.getSymKey = exports.formatISODate = exports.getTimeSeries = exports.getSubscriptionTopic = exports.findSubscriptionForTrigger = exports.findTopKey = exports.XSleepFor = exports.matchesStatus = exports.matchesStatusCode = exports.identifyRedisTypeFromClass = exports.polyfill = exports.identifyRedisType = exports.deterministicRandom = exports.guid = exports.sleepFor = void 0;
|
|
4
|
+
const nanoid_1 = require("nanoid");
|
|
4
5
|
async function sleepFor(ms) {
|
|
5
6
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6
7
|
}
|
|
7
8
|
exports.sleepFor = sleepFor;
|
|
9
|
+
function guid() {
|
|
10
|
+
return (0, nanoid_1.nanoid)();
|
|
11
|
+
}
|
|
12
|
+
exports.guid = guid;
|
|
8
13
|
function deterministicRandom(seed) {
|
|
9
14
|
let x = Math.sin(seed) * 10000;
|
|
10
15
|
return x - Math.floor(x);
|
package/build/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hotmeshio/hotmesh",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.35",
|
|
4
4
|
"description": "Unbreakable Workflows",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"test:emit": "NODE_ENV=test jest ./tests/functional/emit/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
31
31
|
"test:hook": "NODE_ENV=test jest ./tests/functional/hook/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
32
32
|
"test:signal": "NODE_ENV=test jest ./tests/functional/signal/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
33
|
+
"test:interrupt": "NODE_ENV=test jest ./tests/functional/interrupt/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
33
34
|
"test:parallel": "NODE_ENV=test jest ./tests/functional/parallel/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
34
35
|
"test:sequence": "NODE_ENV=test jest ./tests/functional/sequence/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
35
36
|
"test:quorum": "NODE_ENV=test jest ./tests/functional/quorum/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
@@ -46,6 +47,7 @@
|
|
|
46
47
|
"test:durable": "NODE_ENV=test jest ./tests/durable/*/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
47
48
|
"test:durable:meshos": "NODE_ENV=test jest ./tests/durable/meshos/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
48
49
|
"test:durable:hello": "NODE_ENV=test jest ./tests/durable/helloworld/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
50
|
+
"test:durable:interrupt": "NODE_ENV=test jest ./tests/durable/interrupt/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
49
51
|
"test:durable:goodbye": "NODE_ENV=test jest ./tests/durable/goodbye/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
50
52
|
"test:durable:hook": "NODE_ENV=test jest ./tests/durable/hook/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
51
53
|
"test:durable:retry": "NODE_ENV=test jest ./tests/durable/retry/index.test.ts --detectOpenHandles --forceExit --verbose",
|
|
@@ -58,5 +58,10 @@ declare class Activity {
|
|
|
58
58
|
resolveAdjacentDad(): string;
|
|
59
59
|
filterAdjacent(): Promise<StreamData[]>;
|
|
60
60
|
transition(adjacencyList: StreamData[], jobStatus: JobStatus): Promise<string[]>;
|
|
61
|
+
/**
|
|
62
|
+
* A job with a vale < -100_000_000 is considered interrupted,
|
|
63
|
+
* as the interruption event decrements the job status by 1billion.
|
|
64
|
+
*/
|
|
65
|
+
jobWasInterrupted(jobStatus: JobStatus): boolean;
|
|
61
66
|
}
|
|
62
67
|
export { Activity, ActivityType };
|
|
@@ -9,6 +9,7 @@ const pipe_1 = require("../pipe");
|
|
|
9
9
|
const serializer_1 = require("../serializer");
|
|
10
10
|
const telemetry_1 = require("../telemetry");
|
|
11
11
|
const stream_1 = require("../../types/stream");
|
|
12
|
+
const enums_1 = require("../../modules/enums");
|
|
12
13
|
/**
|
|
13
14
|
* The base class for all activities
|
|
14
15
|
*/
|
|
@@ -44,6 +45,7 @@ class Activity {
|
|
|
44
45
|
let telemetry;
|
|
45
46
|
try {
|
|
46
47
|
await this.getState();
|
|
48
|
+
collator_1.CollatorService.assertJobActive(this.context.metadata.js, this.context.metadata.jid, this.metadata.aid);
|
|
47
49
|
const aState = await collator_1.CollatorService.notarizeReentry(this);
|
|
48
50
|
this.adjacentIndex = collator_1.CollatorService.getDimensionalIndex(aState);
|
|
49
51
|
telemetry = new telemetry_1.TelemetryService(this.engine.appId, this.config, this.metadata, this.context);
|
|
@@ -71,12 +73,20 @@ class Activity {
|
|
|
71
73
|
this.logger.info('process-event-inactive-error', { error });
|
|
72
74
|
return;
|
|
73
75
|
}
|
|
76
|
+
else if (error instanceof errors_1.InactiveJobError) {
|
|
77
|
+
this.logger.info('process-event-inactive-job-error', { error });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
else if (error instanceof errors_1.GetStateError) {
|
|
81
|
+
this.logger.info('process-event-get-job-error', { error });
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
74
84
|
this.logger.error('activity-process-event-error', { error });
|
|
75
85
|
telemetry && telemetry.setActivityError(error.message);
|
|
76
86
|
throw error;
|
|
77
87
|
}
|
|
78
88
|
finally {
|
|
79
|
-
telemetry
|
|
89
|
+
telemetry?.endActivitySpan();
|
|
80
90
|
this.logger.debug('activity-process-event-end', { jid, aid });
|
|
81
91
|
}
|
|
82
92
|
}
|
|
@@ -113,6 +123,7 @@ class Activity {
|
|
|
113
123
|
telemetry.mapActivityAttributes();
|
|
114
124
|
const jobStatus = this.resolveStatus(multiResponse);
|
|
115
125
|
const attrs = { 'app.job.jss': jobStatus };
|
|
126
|
+
//adjacencyList membership has already been set at this point (according to activity status)
|
|
116
127
|
const messageIds = await this.transition(this.adjacencyList, jobStatus);
|
|
117
128
|
if (messageIds.length) {
|
|
118
129
|
attrs['app.activity.mids'] = messageIds.join(',');
|
|
@@ -307,11 +318,12 @@ class Activity {
|
|
|
307
318
|
self.hook = {};
|
|
308
319
|
}
|
|
309
320
|
context['$self'] = self;
|
|
310
|
-
context['$job'] = context; //NEVER call STRINGIFY! (circular)
|
|
321
|
+
context['$job'] = context; //NEVER call STRINGIFY! (now circular)
|
|
311
322
|
return context;
|
|
312
323
|
}
|
|
313
324
|
initPolicies(context) {
|
|
314
|
-
|
|
325
|
+
const expire = pipe_1.Pipe.resolve(this.config.expire ?? enums_1.EXPIRE_DURATION, context);
|
|
326
|
+
context.metadata.expire = expire;
|
|
315
327
|
}
|
|
316
328
|
bindActivityData(type) {
|
|
317
329
|
this.context[this.metadata.aid][type].data = this.data;
|
|
@@ -341,6 +353,7 @@ class Activity {
|
|
|
341
353
|
if (mapper_1.MapperService.evaluate(transitionRule, this.context, this.code)) {
|
|
342
354
|
adjacencyList.push({
|
|
343
355
|
metadata: {
|
|
356
|
+
guid: (0, utils_1.guid)(),
|
|
344
357
|
jid: this.context.metadata.jid,
|
|
345
358
|
dad: adjacentDad,
|
|
346
359
|
aid: toActivityId,
|
|
@@ -356,15 +369,16 @@ class Activity {
|
|
|
356
369
|
return adjacencyList;
|
|
357
370
|
}
|
|
358
371
|
async transition(adjacencyList, jobStatus) {
|
|
372
|
+
if (this.jobWasInterrupted(jobStatus)) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
359
375
|
let mIds = [];
|
|
360
376
|
let emit = false;
|
|
361
377
|
if (this.config.emit) {
|
|
362
378
|
emit = pipe_1.Pipe.resolve(this.config.emit, this.context);
|
|
363
379
|
}
|
|
364
380
|
if (jobStatus <= 0 || emit) {
|
|
365
|
-
|
|
366
|
-
const isTrueEmit = jobStatus > 0;
|
|
367
|
-
await this.engine.runJobCompletionTasks(this.context, isTrueEmit);
|
|
381
|
+
await this.engine.runJobCompletionTasks(this.context, { emit: jobStatus > 0 });
|
|
368
382
|
}
|
|
369
383
|
if (adjacencyList.length && jobStatus > 0) {
|
|
370
384
|
const multi = this.store.getMulti();
|
|
@@ -375,5 +389,12 @@ class Activity {
|
|
|
375
389
|
}
|
|
376
390
|
return mIds;
|
|
377
391
|
}
|
|
392
|
+
/**
|
|
393
|
+
* A job with a vale < -100_000_000 is considered interrupted,
|
|
394
|
+
* as the interruption event decrements the job status by 1billion.
|
|
395
|
+
*/
|
|
396
|
+
jobWasInterrupted(jobStatus) {
|
|
397
|
+
return jobStatus < -100000000;
|
|
398
|
+
}
|
|
378
399
|
}
|
|
379
400
|
exports.Activity = Activity;
|
|
@@ -7,6 +7,7 @@ const collator_1 = require("../collator");
|
|
|
7
7
|
const stream_1 = require("../../types/stream");
|
|
8
8
|
const telemetry_1 = require("../telemetry");
|
|
9
9
|
const pipe_1 = require("../pipe");
|
|
10
|
+
const utils_1 = require("../../modules/utils");
|
|
10
11
|
class Await extends activity_1.Activity {
|
|
11
12
|
constructor(config, data, metadata, hook, engine, context) {
|
|
12
13
|
super(config, data, metadata, hook, engine, context);
|
|
@@ -20,6 +21,7 @@ class Await extends activity_1.Activity {
|
|
|
20
21
|
this.setLeg(1);
|
|
21
22
|
await collator_1.CollatorService.notarizeEntry(this);
|
|
22
23
|
await this.getState();
|
|
24
|
+
collator_1.CollatorService.assertJobActive(this.context.metadata.js, this.context.metadata.jid, this.metadata.aid);
|
|
23
25
|
telemetry = new telemetry_1.TelemetryService(this.engine.appId, this.config, this.metadata, this.context);
|
|
24
26
|
telemetry.startActivitySpan(this.leg);
|
|
25
27
|
this.mapInputData();
|
|
@@ -41,17 +43,22 @@ class Await extends activity_1.Activity {
|
|
|
41
43
|
return this.context.metadata.aid;
|
|
42
44
|
}
|
|
43
45
|
catch (error) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
if (error instanceof errors_1.InactiveJobError) {
|
|
47
|
+
this.logger.error('await-inactive-job-error', { error });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
else if (error instanceof errors_1.GetStateError) {
|
|
46
51
|
this.logger.error('await-get-state-error', { error });
|
|
52
|
+
return;
|
|
47
53
|
}
|
|
48
54
|
else {
|
|
49
55
|
this.logger.error('await-process-error', { error });
|
|
50
56
|
}
|
|
57
|
+
telemetry.setActivityError(error.message);
|
|
51
58
|
throw error;
|
|
52
59
|
}
|
|
53
60
|
finally {
|
|
54
|
-
telemetry
|
|
61
|
+
telemetry?.endActivitySpan();
|
|
55
62
|
this.logger.debug('await-process-end', { jid: this.context.metadata.jid, aid: this.metadata.aid });
|
|
56
63
|
}
|
|
57
64
|
}
|
|
@@ -59,6 +66,7 @@ class Await extends activity_1.Activity {
|
|
|
59
66
|
const topic = pipe_1.Pipe.resolve(this.config.subtype, this.context);
|
|
60
67
|
const streamData = {
|
|
61
68
|
metadata: {
|
|
69
|
+
guid: (0, utils_1.guid)(),
|
|
62
70
|
jid: this.context.metadata.jid,
|
|
63
71
|
dad: this.metadata.dad,
|
|
64
72
|
aid: this.metadata.aid,
|
|
@@ -5,6 +5,7 @@ const errors_1 = require("../../modules/errors");
|
|
|
5
5
|
const collator_1 = require("../collator");
|
|
6
6
|
const activity_1 = require("./activity");
|
|
7
7
|
const telemetry_1 = require("../telemetry");
|
|
8
|
+
const utils_1 = require("../../modules/utils");
|
|
8
9
|
class Cycle extends activity_1.Activity {
|
|
9
10
|
constructor(config, data, metadata, hook, engine, context) {
|
|
10
11
|
super(config, data, metadata, hook, engine, context);
|
|
@@ -18,6 +19,7 @@ class Cycle extends activity_1.Activity {
|
|
|
18
19
|
this.setLeg(1);
|
|
19
20
|
await collator_1.CollatorService.notarizeEntry(this);
|
|
20
21
|
await this.getState();
|
|
22
|
+
collator_1.CollatorService.assertJobActive(this.context.metadata.js, this.context.metadata.jid, this.metadata.aid);
|
|
21
23
|
telemetry = new telemetry_1.TelemetryService(this.engine.appId, this.config, this.metadata, this.context);
|
|
22
24
|
telemetry.startActivitySpan(this.leg);
|
|
23
25
|
this.mapInputData();
|
|
@@ -41,8 +43,13 @@ class Cycle extends activity_1.Activity {
|
|
|
41
43
|
return this.context.metadata.aid;
|
|
42
44
|
}
|
|
43
45
|
catch (error) {
|
|
44
|
-
if (error instanceof errors_1.
|
|
46
|
+
if (error instanceof errors_1.InactiveJobError) {
|
|
47
|
+
this.logger.error('cycle-inactive-job-error', { error });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
else if (error instanceof errors_1.GetStateError) {
|
|
45
51
|
this.logger.error('cycle-get-state-error', { error });
|
|
52
|
+
return;
|
|
46
53
|
}
|
|
47
54
|
else {
|
|
48
55
|
this.logger.error('cycle-process-error', { error });
|
|
@@ -51,7 +58,7 @@ class Cycle extends activity_1.Activity {
|
|
|
51
58
|
throw error;
|
|
52
59
|
}
|
|
53
60
|
finally {
|
|
54
|
-
telemetry
|
|
61
|
+
telemetry?.endActivitySpan();
|
|
55
62
|
this.logger.debug('cycle-process-end', { jid: this.context.metadata.jid, aid: this.metadata.aid });
|
|
56
63
|
}
|
|
57
64
|
}
|
|
@@ -70,6 +77,7 @@ class Cycle extends activity_1.Activity {
|
|
|
70
77
|
this.mapInputData();
|
|
71
78
|
const streamData = {
|
|
72
79
|
metadata: {
|
|
80
|
+
guid: (0, utils_1.guid)(),
|
|
73
81
|
dad: collator_1.CollatorService.resolveReentryDimension(this),
|
|
74
82
|
jid: this.context.metadata.jid,
|
|
75
83
|
aid: this.config.ancestor,
|
|
@@ -23,6 +23,7 @@ class Hook extends activity_1.Activity {
|
|
|
23
23
|
this.setLeg(1);
|
|
24
24
|
await collator_1.CollatorService.notarizeEntry(this);
|
|
25
25
|
await this.getState();
|
|
26
|
+
collator_1.CollatorService.assertJobActive(this.context.metadata.js, this.context.metadata.jid, this.metadata.aid);
|
|
26
27
|
telemetry = new telemetry_1.TelemetryService(this.engine.appId, this.config, this.metadata, this.context);
|
|
27
28
|
telemetry.startActivitySpan(this.leg);
|
|
28
29
|
let multiResponse;
|
|
@@ -59,8 +60,13 @@ class Hook extends activity_1.Activity {
|
|
|
59
60
|
return this.context.metadata.aid;
|
|
60
61
|
}
|
|
61
62
|
catch (error) {
|
|
62
|
-
if (error instanceof errors_1.
|
|
63
|
+
if (error instanceof errors_1.InactiveJobError) {
|
|
64
|
+
this.logger.error('hook-inactive-job-error', { error });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
else if (error instanceof errors_1.GetStateError) {
|
|
63
68
|
this.logger.error('hook-get-state-error', { error });
|
|
69
|
+
return;
|
|
64
70
|
}
|
|
65
71
|
else {
|
|
66
72
|
this.logger.error('hook-process-error', { error });
|
|
@@ -69,7 +75,7 @@ class Hook extends activity_1.Activity {
|
|
|
69
75
|
throw error;
|
|
70
76
|
}
|
|
71
77
|
finally {
|
|
72
|
-
telemetry
|
|
78
|
+
telemetry?.endActivitySpan();
|
|
73
79
|
this.logger.debug('hook-process-end', { jid: this.context.metadata.jid, aid: this.metadata.aid });
|
|
74
80
|
}
|
|
75
81
|
}
|
|
@@ -2,7 +2,7 @@ import { Activity } from './activity';
|
|
|
2
2
|
import { Await } from './await';
|
|
3
3
|
import { Cycle } from './cycle';
|
|
4
4
|
import { Hook } from './hook';
|
|
5
|
-
import {
|
|
5
|
+
import { Interrupt } from './interrupt';
|
|
6
6
|
import { Signal } from './signal';
|
|
7
7
|
import { Trigger } from './trigger';
|
|
8
8
|
import { Worker } from './worker';
|
|
@@ -11,7 +11,7 @@ declare const _default: {
|
|
|
11
11
|
await: typeof Await;
|
|
12
12
|
cycle: typeof Cycle;
|
|
13
13
|
hook: typeof Hook;
|
|
14
|
-
|
|
14
|
+
interrupt: typeof Interrupt;
|
|
15
15
|
signal: typeof Signal;
|
|
16
16
|
trigger: typeof Trigger;
|
|
17
17
|
worker: typeof Worker;
|