@bluelibs/runner 2.2.3 → 3.0.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 +1315 -942
- package/dist/common.types.d.ts +20 -0
- package/dist/common.types.js +4 -0
- package/dist/common.types.js.map +1 -0
- package/dist/context.d.ts +34 -0
- package/dist/context.js +58 -0
- package/dist/context.js.map +1 -0
- package/dist/define.d.ts +22 -3
- package/dist/define.js +52 -8
- package/dist/define.js.map +1 -1
- package/dist/defs.d.ts +52 -31
- package/dist/defs.js +10 -2
- package/dist/defs.js.map +1 -1
- package/dist/errors.js +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/event.types.d.ts +18 -0
- package/dist/event.types.js +4 -0
- package/dist/event.types.js.map +1 -0
- package/dist/examples/registrator-example.d.ts +122 -0
- package/dist/examples/registrator-example.js +147 -0
- package/dist/examples/registrator-example.js.map +1 -0
- package/dist/globals/globalEvents.d.ts +41 -0
- package/dist/globals/globalEvents.js +94 -0
- package/dist/globals/globalEvents.js.map +1 -0
- package/dist/globals/globalMiddleware.d.ts +23 -0
- package/dist/globals/globalMiddleware.js +15 -0
- package/dist/globals/globalMiddleware.js.map +1 -0
- package/dist/globals/globalResources.d.ts +27 -0
- package/dist/globals/globalResources.js +47 -0
- package/dist/globals/globalResources.js.map +1 -0
- package/dist/globals/middleware/cache.middleware.d.ts +34 -0
- package/dist/globals/middleware/cache.middleware.js +85 -0
- package/dist/globals/middleware/cache.middleware.js.map +1 -0
- package/dist/globals/middleware/requireContext.middleware.d.ts +6 -0
- package/dist/globals/middleware/requireContext.middleware.js +25 -0
- package/dist/globals/middleware/requireContext.middleware.js.map +1 -0
- package/dist/globals/middleware/retry.middleware.d.ts +20 -0
- package/dist/globals/middleware/retry.middleware.js +34 -0
- package/dist/globals/middleware/retry.middleware.js.map +1 -0
- package/dist/globals/resources/queue.resource.d.ts +7 -0
- package/dist/globals/resources/queue.resource.js +31 -0
- package/dist/globals/resources/queue.resource.js.map +1 -0
- package/dist/index.d.ts +45 -9
- package/dist/index.js +14 -9
- package/dist/index.js.map +1 -1
- package/dist/middleware.types.d.ts +40 -0
- package/dist/middleware.types.js +4 -0
- package/dist/middleware.types.js.map +1 -0
- package/dist/models/DependencyProcessor.d.ts +2 -1
- package/dist/models/DependencyProcessor.js +11 -13
- package/dist/models/DependencyProcessor.js.map +1 -1
- package/dist/models/EventManager.d.ts +5 -0
- package/dist/models/EventManager.js +44 -2
- package/dist/models/EventManager.js.map +1 -1
- package/dist/models/Logger.d.ts +30 -12
- package/dist/models/Logger.js +130 -42
- package/dist/models/Logger.js.map +1 -1
- package/dist/models/OverrideManager.d.ts +13 -0
- package/dist/models/OverrideManager.js +70 -0
- package/dist/models/OverrideManager.js.map +1 -0
- package/dist/models/Queue.d.ts +25 -0
- package/dist/models/Queue.js +54 -0
- package/dist/models/Queue.js.map +1 -0
- package/dist/models/ResourceInitializer.d.ts +5 -2
- package/dist/models/ResourceInitializer.js +20 -14
- package/dist/models/ResourceInitializer.js.map +1 -1
- package/dist/models/Semaphore.d.ts +61 -0
- package/dist/models/Semaphore.js +166 -0
- package/dist/models/Semaphore.js.map +1 -0
- package/dist/models/Store.d.ts +17 -72
- package/dist/models/Store.js +71 -269
- package/dist/models/Store.js.map +1 -1
- package/dist/models/StoreConstants.d.ts +11 -0
- package/dist/models/StoreConstants.js +18 -0
- package/dist/models/StoreConstants.js.map +1 -0
- package/dist/models/StoreRegistry.d.ts +25 -0
- package/dist/models/StoreRegistry.js +171 -0
- package/dist/models/StoreRegistry.js.map +1 -0
- package/dist/models/StoreTypes.d.ts +21 -0
- package/dist/models/StoreTypes.js +3 -0
- package/dist/models/StoreTypes.js.map +1 -0
- package/dist/models/StoreValidator.d.ts +10 -0
- package/dist/models/StoreValidator.js +41 -0
- package/dist/models/StoreValidator.js.map +1 -0
- package/dist/models/TaskRunner.js +39 -24
- package/dist/models/TaskRunner.js.map +1 -1
- package/dist/models/VarStore.d.ts +17 -0
- package/dist/models/VarStore.js +60 -0
- package/dist/models/VarStore.js.map +1 -0
- package/dist/models/index.d.ts +3 -0
- package/dist/models/index.js +3 -0
- package/dist/models/index.js.map +1 -1
- package/dist/resource.types.d.ts +31 -0
- package/dist/resource.types.js +3 -0
- package/dist/resource.types.js.map +1 -0
- package/dist/run.d.ts +4 -1
- package/dist/run.js +6 -3
- package/dist/run.js.map +1 -1
- package/dist/symbols.d.ts +24 -0
- package/dist/symbols.js +29 -0
- package/dist/symbols.js.map +1 -0
- package/dist/task.types.d.ts +55 -0
- package/dist/task.types.js +23 -0
- package/dist/task.types.js.map +1 -0
- package/dist/tools/registratorId.d.ts +4 -0
- package/dist/tools/registratorId.js +40 -0
- package/dist/tools/registratorId.js.map +1 -0
- package/dist/tools/simpleHash.d.ts +9 -0
- package/dist/tools/simpleHash.js +34 -0
- package/dist/tools/simpleHash.js.map +1 -0
- package/dist/types/base-interfaces.d.ts +18 -0
- package/dist/types/base-interfaces.js +6 -0
- package/dist/types/base-interfaces.js.map +1 -0
- package/dist/types/base.d.ts +13 -0
- package/dist/types/base.js +3 -0
- package/dist/types/base.js.map +1 -0
- package/dist/types/dependencies.d.ts +22 -0
- package/dist/types/dependencies.js +3 -0
- package/dist/types/dependencies.js.map +1 -0
- package/dist/types/dependency-core.d.ts +14 -0
- package/dist/types/dependency-core.js +5 -0
- package/dist/types/dependency-core.js.map +1 -0
- package/dist/types/events.d.ts +52 -0
- package/dist/types/events.js +6 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/hooks.d.ts +16 -0
- package/dist/types/hooks.js +5 -0
- package/dist/types/hooks.js.map +1 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.js +27 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/meta.d.ts +13 -0
- package/dist/types/meta.js +5 -0
- package/dist/types/meta.js.map +1 -0
- package/dist/types/middleware.d.ts +38 -0
- package/dist/types/middleware.js +6 -0
- package/dist/types/middleware.js.map +1 -0
- package/dist/types/registerable.d.ts +10 -0
- package/dist/types/registerable.js +5 -0
- package/dist/types/registerable.js.map +1 -0
- package/dist/types/resources.d.ts +44 -0
- package/dist/types/resources.js +5 -0
- package/dist/types/resources.js.map +1 -0
- package/dist/types/symbols.d.ts +24 -0
- package/dist/types/symbols.js +30 -0
- package/dist/types/symbols.js.map +1 -0
- package/dist/types/tasks.d.ts +41 -0
- package/dist/types/tasks.js +5 -0
- package/dist/types/tasks.js.map +1 -0
- package/dist/types/utilities.d.ts +7 -0
- package/dist/types/utilities.js +5 -0
- package/dist/types/utilities.js.map +1 -0
- package/package.json +10 -6
- package/src/__tests__/benchmark/benchmark.test.ts +1 -1
- package/src/__tests__/context.test.ts +91 -0
- package/src/__tests__/errors.test.ts +8 -5
- package/src/__tests__/globalEvents.test.ts +1 -1
- package/src/__tests__/globals/cache.middleware.test.ts +772 -0
- package/src/__tests__/globals/queue.resource.test.ts +141 -0
- package/src/__tests__/globals/requireContext.middleware.test.ts +98 -0
- package/src/__tests__/globals/retry.middleware.test.ts +157 -0
- package/src/__tests__/index.helper.test.ts +55 -0
- package/src/__tests__/models/EventManager.test.ts +144 -0
- package/src/__tests__/models/Logger.test.ts +291 -34
- package/src/__tests__/models/Queue.test.ts +189 -0
- package/src/__tests__/models/ResourceInitializer.test.ts +8 -6
- package/src/__tests__/models/Semaphore.test.ts +713 -0
- package/src/__tests__/models/Store.test.ts +40 -0
- package/src/__tests__/models/TaskRunner.test.ts +86 -5
- package/src/__tests__/run.middleware.test.ts +166 -12
- package/src/__tests__/run.overrides.test.ts +13 -10
- package/src/__tests__/run.test.ts +363 -12
- package/src/__tests__/setOutput.test.ts +244 -0
- package/src/__tests__/tools/getCallerFile.test.ts +9 -9
- package/src/__tests__/typesafety.test.ts +54 -39
- package/src/context.ts +86 -0
- package/src/define.ts +84 -14
- package/src/defs.ts +91 -41
- package/src/errors.ts +3 -1
- package/src/{globalEvents.ts → globals/globalEvents.ts} +13 -12
- package/src/globals/globalMiddleware.ts +14 -0
- package/src/{globalResources.ts → globals/globalResources.ts} +14 -10
- package/src/globals/middleware/cache.middleware.ts +115 -0
- package/src/globals/middleware/requireContext.middleware.ts +36 -0
- package/src/globals/middleware/retry.middleware.ts +56 -0
- package/src/globals/resources/queue.resource.ts +34 -0
- package/src/index.ts +9 -5
- package/src/models/DependencyProcessor.ts +36 -40
- package/src/models/EventManager.ts +45 -5
- package/src/models/Logger.ts +170 -48
- package/src/models/OverrideManager.ts +84 -0
- package/src/models/Queue.ts +66 -0
- package/src/models/ResourceInitializer.ts +38 -20
- package/src/models/Semaphore.ts +208 -0
- package/src/models/Store.ts +94 -342
- package/src/models/StoreConstants.ts +17 -0
- package/src/models/StoreRegistry.ts +217 -0
- package/src/models/StoreTypes.ts +46 -0
- package/src/models/StoreValidator.ts +38 -0
- package/src/models/TaskRunner.ts +53 -40
- package/src/models/index.ts +3 -0
- package/src/run.ts +7 -4
- package/src/__tests__/index.ts +0 -15
- package/src/examples/express-mongo/index.ts +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { defineEvent } from "
|
|
2
|
-
import { ITask, IResource, IEvent } from "
|
|
3
|
-
import { ILog } from "
|
|
1
|
+
import { defineEvent } from "../define";
|
|
2
|
+
import { ITask, IResource, IEvent } from "../defs";
|
|
3
|
+
import { ILog } from "../models/Logger";
|
|
4
4
|
|
|
5
5
|
export const globalEvents = {
|
|
6
6
|
beforeInit: defineEvent({
|
|
7
|
-
id: "
|
|
7
|
+
id: "globals.events.beforeInit",
|
|
8
8
|
meta: {
|
|
9
9
|
title: "Before Initialization",
|
|
10
10
|
description:
|
|
@@ -13,7 +13,7 @@ export const globalEvents = {
|
|
|
13
13
|
},
|
|
14
14
|
}),
|
|
15
15
|
afterInit: defineEvent({
|
|
16
|
-
id: "
|
|
16
|
+
id: "globals.events.afterInit",
|
|
17
17
|
meta: {
|
|
18
18
|
title: "After Initialization",
|
|
19
19
|
description:
|
|
@@ -22,7 +22,7 @@ export const globalEvents = {
|
|
|
22
22
|
},
|
|
23
23
|
}),
|
|
24
24
|
log: defineEvent<ILog>({
|
|
25
|
-
id: "
|
|
25
|
+
id: "globals.events.log",
|
|
26
26
|
meta: {
|
|
27
27
|
title: "Log Event",
|
|
28
28
|
description: "Used to log events and messages across the system.",
|
|
@@ -34,7 +34,7 @@ export const globalEvents = {
|
|
|
34
34
|
task: ITask<any, any, any>;
|
|
35
35
|
input: any;
|
|
36
36
|
}>({
|
|
37
|
-
id: "
|
|
37
|
+
id: "globals.events.tasks.beforeRun",
|
|
38
38
|
meta: {
|
|
39
39
|
title: "Before Task Execution",
|
|
40
40
|
description:
|
|
@@ -46,8 +46,9 @@ export const globalEvents = {
|
|
|
46
46
|
task: ITask<any, any, any>;
|
|
47
47
|
input: any;
|
|
48
48
|
output: any;
|
|
49
|
+
setOutput: (newOutput: any) => void;
|
|
49
50
|
}>({
|
|
50
|
-
id: "
|
|
51
|
+
id: "globals.events.tasks.afterRun",
|
|
51
52
|
meta: {
|
|
52
53
|
title: "After Task Execution",
|
|
53
54
|
description:
|
|
@@ -60,7 +61,7 @@ export const globalEvents = {
|
|
|
60
61
|
suppress: () => void;
|
|
61
62
|
task: ITask<any, any, any>;
|
|
62
63
|
}>({
|
|
63
|
-
id: "
|
|
64
|
+
id: "globals.events.tasks.onError",
|
|
64
65
|
meta: {
|
|
65
66
|
title: "Task Error",
|
|
66
67
|
description:
|
|
@@ -74,7 +75,7 @@ export const globalEvents = {
|
|
|
74
75
|
resource: IResource<any, any, any>;
|
|
75
76
|
config: any;
|
|
76
77
|
}>({
|
|
77
|
-
id: "
|
|
78
|
+
id: "globals.events.resources.beforeInit",
|
|
78
79
|
meta: {
|
|
79
80
|
title: "Before Resource Initialization",
|
|
80
81
|
description:
|
|
@@ -87,7 +88,7 @@ export const globalEvents = {
|
|
|
87
88
|
config: any;
|
|
88
89
|
value: any;
|
|
89
90
|
}>({
|
|
90
|
-
id: "
|
|
91
|
+
id: "globals.events.resources.afterInit",
|
|
91
92
|
meta: {
|
|
92
93
|
title: "After Resource Initialization",
|
|
93
94
|
description:
|
|
@@ -100,7 +101,7 @@ export const globalEvents = {
|
|
|
100
101
|
suppress: () => void;
|
|
101
102
|
resource: IResource<any, any, any>;
|
|
102
103
|
}>({
|
|
103
|
-
id: "
|
|
104
|
+
id: "globals.events.resources.onError",
|
|
104
105
|
meta: {
|
|
105
106
|
title: "Resource Error",
|
|
106
107
|
description:
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Context, ContextError } from "../context";
|
|
2
|
+
import { defineMiddleware } from "../define";
|
|
3
|
+
import { cacheMiddleware } from "./middleware/cache.middleware";
|
|
4
|
+
import { requireContextMiddleware } from "./middleware/requireContext.middleware";
|
|
5
|
+
import { retryMiddleware } from "./middleware/retry.middleware";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Global middlewares
|
|
9
|
+
*/
|
|
10
|
+
export const globalMiddlewares = {
|
|
11
|
+
requireContext: requireContextMiddleware,
|
|
12
|
+
retry: retryMiddleware,
|
|
13
|
+
cache: cacheMiddleware,
|
|
14
|
+
};
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { defineResource } from "
|
|
2
|
-
import { EventManager } from "
|
|
3
|
-
import { Logger } from "
|
|
4
|
-
import { Store } from "
|
|
5
|
-
import { TaskRunner } from "
|
|
1
|
+
import { defineResource } from "../define";
|
|
2
|
+
import { EventManager } from "../models/EventManager";
|
|
3
|
+
import { Logger } from "../models/Logger";
|
|
4
|
+
import { Store } from "../models/Store";
|
|
5
|
+
import { TaskRunner } from "../models/TaskRunner";
|
|
6
|
+
import { cacheResource } from "./middleware/cache.middleware";
|
|
7
|
+
import { queueResource } from "./resources/queue.resource";
|
|
6
8
|
|
|
7
9
|
const store = defineResource({
|
|
8
|
-
id: "
|
|
10
|
+
id: "globals.resources.store",
|
|
9
11
|
init: async (store: Store) => store,
|
|
10
12
|
meta: {
|
|
11
13
|
title: "Store",
|
|
@@ -18,7 +20,7 @@ const store = defineResource({
|
|
|
18
20
|
export const globalResources = {
|
|
19
21
|
store,
|
|
20
22
|
eventManager: defineResource({
|
|
21
|
-
id: "
|
|
23
|
+
id: "globals.resources.eventManager",
|
|
22
24
|
init: async (em: EventManager) => em,
|
|
23
25
|
meta: {
|
|
24
26
|
title: "Event Manager",
|
|
@@ -28,7 +30,7 @@ export const globalResources = {
|
|
|
28
30
|
},
|
|
29
31
|
}),
|
|
30
32
|
taskRunner: defineResource({
|
|
31
|
-
id: "
|
|
33
|
+
id: "globals.resources.taskRunner",
|
|
32
34
|
init: async (runner: TaskRunner) => runner,
|
|
33
35
|
meta: {
|
|
34
36
|
title: "Task Runner",
|
|
@@ -38,12 +40,14 @@ export const globalResources = {
|
|
|
38
40
|
},
|
|
39
41
|
}),
|
|
40
42
|
logger: defineResource({
|
|
41
|
-
id: "
|
|
43
|
+
id: "globals.resources.logger",
|
|
42
44
|
init: async (logger: Logger) => logger,
|
|
43
45
|
meta: {
|
|
44
46
|
title: "Logger",
|
|
45
47
|
description:
|
|
46
|
-
"Logs all events and errors. This is meant to be used internally for most use-cases. Emits a
|
|
48
|
+
"Logs all events and errors. This is meant to be used internally for most use-cases. Emits a globals.log event for each log.",
|
|
47
49
|
},
|
|
48
50
|
}),
|
|
51
|
+
cache: cacheResource,
|
|
52
|
+
queue: queueResource,
|
|
49
53
|
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { defineMiddleware, defineResource, defineTask } from "../../define";
|
|
2
|
+
import { LRUCache } from "lru-cache";
|
|
3
|
+
import { IResource, ITask } from "../../defs";
|
|
4
|
+
|
|
5
|
+
export interface ICacheInstance {
|
|
6
|
+
set(key: string, value: any): void;
|
|
7
|
+
get(key: string): any;
|
|
8
|
+
clear(): void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Default cache factory task that can be overridden
|
|
12
|
+
export const cacheFactoryTask = defineTask({
|
|
13
|
+
id: "globals.tasks.cacheFactory",
|
|
14
|
+
run: async (options: any) => {
|
|
15
|
+
return new LRUCache(options) as ICacheInstance;
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
type CacheResourceConfig = {
|
|
20
|
+
defaultOptions?: any;
|
|
21
|
+
/**
|
|
22
|
+
* This specifies whether the cache handler is async or not (get, set, clear)
|
|
23
|
+
* This is for speed purposes.
|
|
24
|
+
*/
|
|
25
|
+
async?: boolean;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
type CacheMiddlewareConfig = {
|
|
29
|
+
keyBuilder?: (taskId: string, input: any) => string;
|
|
30
|
+
} & any;
|
|
31
|
+
|
|
32
|
+
export const cacheResource = defineResource({
|
|
33
|
+
id: "globals.resources.cache",
|
|
34
|
+
register: [cacheFactoryTask],
|
|
35
|
+
dependencies: {
|
|
36
|
+
cacheFactoryTask,
|
|
37
|
+
},
|
|
38
|
+
init: async (config: CacheResourceConfig, { cacheFactoryTask }) => {
|
|
39
|
+
return {
|
|
40
|
+
map: new Map<string, ICacheInstance>(),
|
|
41
|
+
cacheFactoryTask,
|
|
42
|
+
async: config.async,
|
|
43
|
+
defaultOptions: {
|
|
44
|
+
ttl: 10 * 1000,
|
|
45
|
+
max: 100, // Maximum number of items in cache
|
|
46
|
+
ttlAutopurge: true, // Automatically purge expired items
|
|
47
|
+
...config.defaultOptions,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
dispose: async (cache) => {
|
|
52
|
+
for (const cacheInstance of cache.map.values()) {
|
|
53
|
+
await cacheInstance.clear();
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const defaultKeyBuilder = (taskId: string, input: any) =>
|
|
59
|
+
`${taskId}-${JSON.stringify(input)}`;
|
|
60
|
+
|
|
61
|
+
export const cacheMiddleware = defineMiddleware({
|
|
62
|
+
id: "globals.middleware.cache",
|
|
63
|
+
dependencies: { cache: cacheResource },
|
|
64
|
+
async run({ task, resource, next }, deps, config: CacheMiddlewareConfig) {
|
|
65
|
+
const { cache } = deps;
|
|
66
|
+
config = {
|
|
67
|
+
keyBuilder: defaultKeyBuilder,
|
|
68
|
+
ttl: 10 * 1000,
|
|
69
|
+
max: 100, // Maximum number of items in cache
|
|
70
|
+
ttlAutopurge: true, // Automatically purge expired items
|
|
71
|
+
...config,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
if (!task) {
|
|
75
|
+
throw new Error("Cache middleware can only be used in tasks");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const taskId = task.definition.id;
|
|
79
|
+
const isAsync = cache.async;
|
|
80
|
+
let cacheHolderForTask = cache.map.get(taskId);
|
|
81
|
+
if (!cacheHolderForTask) {
|
|
82
|
+
// Extract only LRUCache options, excluding keyBuilder
|
|
83
|
+
const { keyBuilder, ...lruOptions } = config;
|
|
84
|
+
const cacheOptions = {
|
|
85
|
+
...cache.defaultOptions,
|
|
86
|
+
...lruOptions,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// Use the factory task to create the cache instance
|
|
90
|
+
cacheHolderForTask = await cache.cacheFactoryTask(cacheOptions);
|
|
91
|
+
|
|
92
|
+
cache.map.set(taskId, cacheHolderForTask);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const key = config.keyBuilder!(taskId, task.input);
|
|
96
|
+
|
|
97
|
+
const cachedValue = isAsync
|
|
98
|
+
? await cacheHolderForTask.get(key)
|
|
99
|
+
: cacheHolderForTask.get(key);
|
|
100
|
+
|
|
101
|
+
if (cachedValue) {
|
|
102
|
+
return cachedValue;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const result = await next(task.input);
|
|
106
|
+
|
|
107
|
+
if (isAsync) {
|
|
108
|
+
await cacheHolderForTask.set(key, result);
|
|
109
|
+
} else {
|
|
110
|
+
cacheHolderForTask.set(key, result);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return result;
|
|
114
|
+
},
|
|
115
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Context, ContextError } from "../../context";
|
|
2
|
+
import { defineMiddleware } from "../../define";
|
|
3
|
+
|
|
4
|
+
type RequireContextMiddlewareConfig = {
|
|
5
|
+
context: Context<any>;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const requireContextMiddleware = defineMiddleware({
|
|
9
|
+
id: "globals.middleware.requireContext",
|
|
10
|
+
async run(
|
|
11
|
+
{ task, resource, next },
|
|
12
|
+
deps,
|
|
13
|
+
config: RequireContextMiddlewareConfig
|
|
14
|
+
) {
|
|
15
|
+
if (!config.context) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
"Context not available. Did you forget to pass 'context' to the middleware?"
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const ctx = config.context.use();
|
|
22
|
+
if (!ctx) {
|
|
23
|
+
throw new ContextError(
|
|
24
|
+
"Context not available. Did you forget to provide the context via ContextName.provide()?"
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
if (task) {
|
|
28
|
+
return next(task.input);
|
|
29
|
+
}
|
|
30
|
+
if (resource) {
|
|
31
|
+
return next(resource.config);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return next();
|
|
35
|
+
},
|
|
36
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { defineMiddleware } from "../../define";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Configuration options for the retry middleware
|
|
5
|
+
*/
|
|
6
|
+
export interface RetryMiddlewareConfig {
|
|
7
|
+
/**
|
|
8
|
+
* Maximum number of retry attempts (default: 3)
|
|
9
|
+
*/
|
|
10
|
+
retries?: number;
|
|
11
|
+
/**
|
|
12
|
+
* Callback to determine if retry should stop based on error
|
|
13
|
+
* @default () => false (retry all errors)
|
|
14
|
+
*/
|
|
15
|
+
stopRetryIf?: (error: Error) => boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Custom delay strategy function
|
|
18
|
+
* @default Exponential backoff starting at 100ms
|
|
19
|
+
*/
|
|
20
|
+
delayStrategy?: (attempt: number, error: Error) => number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const retryMiddleware = defineMiddleware({
|
|
24
|
+
id: "globals.middleware.retry",
|
|
25
|
+
async run({ task, resource, next }, deps, config: RetryMiddlewareConfig) {
|
|
26
|
+
const input = task ? task.input : resource?.config;
|
|
27
|
+
let attempts = 0;
|
|
28
|
+
|
|
29
|
+
// Set defaults for required parameters
|
|
30
|
+
const maxRetries = config.retries ?? 3;
|
|
31
|
+
const shouldStop = config.stopRetryIf ?? (() => false);
|
|
32
|
+
|
|
33
|
+
while (true) {
|
|
34
|
+
try {
|
|
35
|
+
return await next(input);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
const err = error as Error;
|
|
38
|
+
|
|
39
|
+
if (shouldStop(err) || attempts >= maxRetries) {
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Calculate delay using custom strategy or default exponential backoff
|
|
44
|
+
const delay = config.delayStrategy
|
|
45
|
+
? config.delayStrategy(attempts, err)
|
|
46
|
+
: 100 * Math.pow(2, attempts);
|
|
47
|
+
|
|
48
|
+
if (delay > 0) {
|
|
49
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
attempts++;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { defineResource } from "../../define";
|
|
2
|
+
import { Queue } from "../../models/Queue";
|
|
3
|
+
|
|
4
|
+
export const queueResource = defineResource({
|
|
5
|
+
id: "globals.resources.queue",
|
|
6
|
+
context: () => ({
|
|
7
|
+
map: new Map<string, Queue>(),
|
|
8
|
+
}),
|
|
9
|
+
init: async (_, deps, context) => {
|
|
10
|
+
const map = context.map;
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
map,
|
|
14
|
+
run: <T>(
|
|
15
|
+
id: string,
|
|
16
|
+
task: (signal: AbortSignal) => Promise<T>
|
|
17
|
+
): Promise<T> => {
|
|
18
|
+
if (!map.has(id)) {
|
|
19
|
+
map.set(id, new Queue());
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return map.get(id)!.run(task);
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
dispose: async (value, _, deps, context) => {
|
|
27
|
+
context.map.forEach((queue) => queue.dispose());
|
|
28
|
+
},
|
|
29
|
+
meta: {
|
|
30
|
+
title: "Queue Map",
|
|
31
|
+
description:
|
|
32
|
+
"A global map that can be used to store and retrieve queues. You can run exclusive tasks based on using an id. queue.run(id, task) will run the task in the queue with the given id. If the queue does not exist, it will be created.",
|
|
33
|
+
},
|
|
34
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -3,14 +3,18 @@ import {
|
|
|
3
3
|
defineResource,
|
|
4
4
|
defineEvent,
|
|
5
5
|
defineMiddleware,
|
|
6
|
+
defineIndex,
|
|
6
7
|
} from "./define";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
8
|
+
import { createContext } from "./context";
|
|
9
|
+
import { globalEvents } from "./globals/globalEvents";
|
|
10
|
+
import { globalResources } from "./globals/globalResources";
|
|
11
|
+
import { globalMiddlewares } from "./globals/globalMiddleware";
|
|
9
12
|
import { run } from "./run";
|
|
10
13
|
|
|
11
14
|
const globals = {
|
|
12
15
|
events: globalEvents,
|
|
13
16
|
resources: globalResources,
|
|
17
|
+
middlewares: globalMiddlewares,
|
|
14
18
|
};
|
|
15
19
|
|
|
16
20
|
export { globals };
|
|
@@ -19,10 +23,10 @@ export {
|
|
|
19
23
|
defineResource as resource,
|
|
20
24
|
defineEvent as event,
|
|
21
25
|
defineMiddleware as middleware,
|
|
26
|
+
defineIndex as index,
|
|
22
27
|
run,
|
|
28
|
+
createContext,
|
|
23
29
|
};
|
|
24
30
|
|
|
25
31
|
export * as definitions from "./defs";
|
|
26
|
-
export { Store } from "./models
|
|
27
|
-
export { EventManager } from "./models/EventManager";
|
|
28
|
-
export { TaskRunner } from "./models/TaskRunner";
|
|
32
|
+
export { Semaphore, Store, EventManager, TaskRunner, Queue } from "./models";
|
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
IEventDefinition,
|
|
8
8
|
IEvent,
|
|
9
9
|
} from "../defs";
|
|
10
|
-
import {
|
|
10
|
+
import { Store } from "./Store";
|
|
11
|
+
import { ResourceStoreElementType, TaskStoreElementType } from "./StoreTypes";
|
|
11
12
|
import * as utils from "../define";
|
|
12
13
|
import { EventManager } from "./EventManager";
|
|
13
14
|
import { ResourceInitializer } from "./ResourceInitializer";
|
|
@@ -81,11 +82,14 @@ export class DependencyProcessor {
|
|
|
81
82
|
resource.resource.id !== this.store.root.resource.id
|
|
82
83
|
) {
|
|
83
84
|
await this.processResourceDependencies(resource);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
const { value, context } =
|
|
86
|
+
await this.resourceInitializer.initializeResource(
|
|
87
|
+
resource.resource,
|
|
88
|
+
resource.config,
|
|
89
|
+
resource.computedDependencies as DependencyValuesType<{}>
|
|
90
|
+
);
|
|
91
|
+
resource.context = context;
|
|
92
|
+
resource.value = value;
|
|
89
93
|
}
|
|
90
94
|
}
|
|
91
95
|
}
|
|
@@ -107,13 +111,16 @@ export class DependencyProcessor {
|
|
|
107
111
|
public async initializeRoot() {
|
|
108
112
|
const storeResource = this.store.root;
|
|
109
113
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
const { value, context } =
|
|
115
|
+
await this.resourceInitializer.initializeResource(
|
|
116
|
+
storeResource.resource,
|
|
117
|
+
storeResource.config,
|
|
118
|
+
// They are already computed
|
|
119
|
+
storeResource.computedDependencies as DependencyValuesType<{}>
|
|
120
|
+
);
|
|
116
121
|
|
|
122
|
+
storeResource.context = context;
|
|
123
|
+
storeResource.value = value;
|
|
117
124
|
storeResource.isInitialized = true;
|
|
118
125
|
}
|
|
119
126
|
|
|
@@ -132,18 +139,6 @@ export class DependencyProcessor {
|
|
|
132
139
|
return;
|
|
133
140
|
}
|
|
134
141
|
|
|
135
|
-
this.logger.debug(
|
|
136
|
-
{
|
|
137
|
-
message:
|
|
138
|
-
eventDefinition === "*"
|
|
139
|
-
? `Task ${task.task.id} being triggered by all events`
|
|
140
|
-
: `Task ${task.task.id} being triggered by event: ${eventDefinition.id}`,
|
|
141
|
-
|
|
142
|
-
event: receivedEvent,
|
|
143
|
-
},
|
|
144
|
-
task.task.id
|
|
145
|
-
);
|
|
146
|
-
|
|
147
142
|
return this.taskRunner.run(
|
|
148
143
|
task.task,
|
|
149
144
|
receivedEvent,
|
|
@@ -180,7 +175,7 @@ export class DependencyProcessor {
|
|
|
180
175
|
return object;
|
|
181
176
|
}
|
|
182
177
|
|
|
183
|
-
async extractDependency(object, source: string) {
|
|
178
|
+
async extractDependency(object: any, source: string) {
|
|
184
179
|
if (utils.isResource(object)) {
|
|
185
180
|
return this.extractResourceDependency(object);
|
|
186
181
|
} else if (utils.isTask(object)) {
|
|
@@ -201,15 +196,7 @@ export class DependencyProcessor {
|
|
|
201
196
|
object: IEventDefinition<Record<string, any>>,
|
|
202
197
|
source: string
|
|
203
198
|
) {
|
|
204
|
-
return async (input) => {
|
|
205
|
-
// runs it in background.
|
|
206
|
-
this.logger.debug(
|
|
207
|
-
{
|
|
208
|
-
message: `Event ${object.id} was emitted from ${source}`,
|
|
209
|
-
},
|
|
210
|
-
source
|
|
211
|
-
);
|
|
212
|
-
|
|
199
|
+
return async (input: any) => {
|
|
213
200
|
return this.eventManager.emit(object, input, source);
|
|
214
201
|
};
|
|
215
202
|
}
|
|
@@ -232,7 +219,7 @@ export class DependencyProcessor {
|
|
|
232
219
|
);
|
|
233
220
|
}
|
|
234
221
|
|
|
235
|
-
return (input) => {
|
|
222
|
+
return (input: any) => {
|
|
236
223
|
return this.taskRunner.run(
|
|
237
224
|
storeTask.task,
|
|
238
225
|
input,
|
|
@@ -256,11 +243,20 @@ export class DependencyProcessor {
|
|
|
256
243
|
storeResource.isInitialized = true;
|
|
257
244
|
|
|
258
245
|
// check if it has an initialisation function that provides the value
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
246
|
+
if (resource.init) {
|
|
247
|
+
const { value, context } =
|
|
248
|
+
await this.resourceInitializer.initializeResource(
|
|
249
|
+
resource,
|
|
250
|
+
config,
|
|
251
|
+
await this.extractDependencies(
|
|
252
|
+
resource.dependencies || {},
|
|
253
|
+
resource.id
|
|
254
|
+
)
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
storeResource.context = context;
|
|
258
|
+
storeResource.value = value;
|
|
259
|
+
}
|
|
264
260
|
}
|
|
265
261
|
|
|
266
262
|
return storeResource.value;
|
|
@@ -22,6 +22,8 @@ export interface IEventHandlerOptions<T = any> {
|
|
|
22
22
|
export class EventManager {
|
|
23
23
|
private listeners: Map<string, IListenerStorage[]> = new Map();
|
|
24
24
|
private globalListeners: IListenerStorage[] = [];
|
|
25
|
+
private cachedMergedListeners: Map<string, IListenerStorage[]> = new Map();
|
|
26
|
+
private globalListenersCacheValid = true;
|
|
25
27
|
#isLocked = false;
|
|
26
28
|
|
|
27
29
|
get isLocked() {
|
|
@@ -57,16 +59,47 @@ export class EventManager {
|
|
|
57
59
|
return result;
|
|
58
60
|
}
|
|
59
61
|
|
|
62
|
+
private getCachedMergedListeners(eventId: string): IListenerStorage[] {
|
|
63
|
+
if (!this.globalListenersCacheValid) {
|
|
64
|
+
this.cachedMergedListeners.clear();
|
|
65
|
+
this.globalListenersCacheValid = true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let cached = this.cachedMergedListeners.get(eventId);
|
|
69
|
+
if (!cached) {
|
|
70
|
+
const eventListeners = this.listeners.get(eventId) || [];
|
|
71
|
+
if (eventListeners.length === 0 && this.globalListeners.length === 0) {
|
|
72
|
+
cached = [];
|
|
73
|
+
} else if (eventListeners.length === 0) {
|
|
74
|
+
cached = this.globalListeners;
|
|
75
|
+
} else if (this.globalListeners.length === 0) {
|
|
76
|
+
cached = eventListeners;
|
|
77
|
+
} else {
|
|
78
|
+
cached = this.mergeSortedListeners(eventListeners, this.globalListeners);
|
|
79
|
+
}
|
|
80
|
+
this.cachedMergedListeners.set(eventId, cached);
|
|
81
|
+
}
|
|
82
|
+
return cached;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private invalidateCache(eventId?: string): void {
|
|
86
|
+
if (eventId) {
|
|
87
|
+
this.cachedMergedListeners.delete(eventId);
|
|
88
|
+
} else {
|
|
89
|
+
this.globalListenersCacheValid = false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
60
93
|
async emit<TInput>(
|
|
61
94
|
eventDefinition: IEventDefinition<TInput>,
|
|
62
95
|
data: TInput,
|
|
63
96
|
source: string
|
|
64
97
|
): Promise<void> {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
98
|
+
const allListeners = this.getCachedMergedListeners(eventDefinition.id);
|
|
99
|
+
|
|
100
|
+
if (allListeners.length === 0) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
70
103
|
|
|
71
104
|
const event: IEvent = {
|
|
72
105
|
id: eventDefinition.id,
|
|
@@ -121,6 +154,7 @@ export class EventManager {
|
|
|
121
154
|
} else {
|
|
122
155
|
this.listeners.set(eventId, [newListener]);
|
|
123
156
|
}
|
|
157
|
+
this.invalidateCache(eventId);
|
|
124
158
|
}
|
|
125
159
|
}
|
|
126
160
|
|
|
@@ -135,5 +169,11 @@ export class EventManager {
|
|
|
135
169
|
filter: options.filter,
|
|
136
170
|
};
|
|
137
171
|
this.insertListener(this.globalListeners, newListener);
|
|
172
|
+
this.invalidateCache();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
hasListeners<T>(eventDefinition: IEventDefinition<T>): boolean {
|
|
176
|
+
const eventListeners = this.listeners.get(eventDefinition.id) || [];
|
|
177
|
+
return eventListeners.length > 0 || this.globalListeners.length > 0;
|
|
138
178
|
}
|
|
139
179
|
}
|