@bluelibs/runner 2.2.4 → 3.1.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 +1409 -935
- 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 +24 -5
- package/dist/define.js +89 -20
- package/dist/define.js.map +1 -1
- package/dist/defs.d.ts +109 -73
- package/dist/defs.js +12 -2
- package/dist/defs.js.map +1 -1
- package/dist/errors.d.ts +5 -5
- package/dist/errors.js +6 -5
- 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 +54 -18
- 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 +6 -5
- package/dist/models/DependencyProcessor.js +13 -15
- package/dist/models/DependencyProcessor.js.map +1 -1
- package/dist/models/EventManager.d.ts +9 -4
- package/dist/models/EventManager.js +44 -2
- package/dist/models/EventManager.js.map +1 -1
- package/dist/models/Logger.d.ts +30 -13
- package/dist/models/Logger.js +132 -54
- 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 +22 -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 +18 -73
- 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.d.ts +1 -1
- 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/getCallerFile.d.ts +9 -1
- package/dist/tools/getCallerFile.js +41 -0
- package/dist/tools/getCallerFile.js.map +1 -1
- 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 +157 -11
- 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.anonymous.test.ts +679 -0
- package/src/__tests__/run.middleware.test.ts +312 -12
- package/src/__tests__/run.overrides.test.ts +13 -10
- package/src/__tests__/run.test.ts +364 -13
- package/src/__tests__/setOutput.test.ts +244 -0
- package/src/__tests__/tools/getCallerFile.test.ts +124 -9
- package/src/__tests__/typesafety.test.ts +71 -41
- package/src/context.ts +86 -0
- package/src/define.ts +129 -34
- package/src/defs.ts +156 -119
- package/src/errors.ts +15 -10
- 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 +42 -49
- package/src/models/EventManager.ts +64 -13
- package/src/models/Logger.ts +181 -64
- package/src/models/OverrideManager.ts +84 -0
- package/src/models/Queue.ts +66 -0
- package/src/models/ResourceInitializer.ts +40 -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 +228 -0
- package/src/models/StoreTypes.ts +46 -0
- package/src/models/StoreValidator.ts +43 -0
- package/src/models/TaskRunner.ts +54 -41
- package/src/models/index.ts +3 -0
- package/src/run.ts +7 -4
- package/src/tools/getCallerFile.ts +54 -2
- package/src/__tests__/index.ts +0 -15
- package/src/examples/express-mongo/index.ts +0 -1
|
@@ -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 | symbol, 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 | symbol, 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";
|
|
@@ -3,11 +3,12 @@ import {
|
|
|
3
3
|
DependencyValuesType,
|
|
4
4
|
ITask,
|
|
5
5
|
IResource,
|
|
6
|
-
IHookDefinition,
|
|
7
6
|
IEventDefinition,
|
|
8
7
|
IEvent,
|
|
8
|
+
IEventEmission,
|
|
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
|
|
|
@@ -125,25 +132,13 @@ export class DependencyProcessor {
|
|
|
125
132
|
if (task.task.on) {
|
|
126
133
|
let eventDefinition = task.task.on;
|
|
127
134
|
|
|
128
|
-
const handler = async (receivedEvent:
|
|
135
|
+
const handler = async (receivedEvent: IEventEmission<any>) => {
|
|
129
136
|
if (receivedEvent.source === task.task.id) {
|
|
130
137
|
// we don't want to trigger the same task that emitted the event
|
|
131
138
|
// process.exit(0);
|
|
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,
|
|
@@ -169,7 +164,7 @@ export class DependencyProcessor {
|
|
|
169
164
|
|
|
170
165
|
async extractDependencies<T extends DependencyMapType>(
|
|
171
166
|
map: T,
|
|
172
|
-
source: string
|
|
167
|
+
source: string | symbol
|
|
173
168
|
): Promise<DependencyValuesType<T>> {
|
|
174
169
|
const object = {} as DependencyValuesType<T>;
|
|
175
170
|
|
|
@@ -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 | symbol) {
|
|
184
179
|
if (utils.isResource(object)) {
|
|
185
180
|
return this.extractResourceDependency(object);
|
|
186
181
|
} else if (utils.isTask(object)) {
|
|
@@ -197,19 +192,8 @@ export class DependencyProcessor {
|
|
|
197
192
|
* @param object
|
|
198
193
|
* @returns
|
|
199
194
|
*/
|
|
200
|
-
extractEventDependency(
|
|
201
|
-
|
|
202
|
-
source: string
|
|
203
|
-
) {
|
|
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
|
-
|
|
195
|
+
extractEventDependency(object: IEvent<any>, source: string | symbol) {
|
|
196
|
+
return async (input: any) => {
|
|
213
197
|
return this.eventManager.emit(object, input, source);
|
|
214
198
|
};
|
|
215
199
|
}
|
|
@@ -217,7 +201,7 @@ export class DependencyProcessor {
|
|
|
217
201
|
async extractTaskDependency(object: ITask<any, any, {}>) {
|
|
218
202
|
const storeTask = this.store.tasks.get(object.id);
|
|
219
203
|
if (storeTask === undefined) {
|
|
220
|
-
throw Errors.dependencyNotFound(`Task ${object.id}`);
|
|
204
|
+
throw Errors.dependencyNotFound(`Task ${object.id.toString()}`);
|
|
221
205
|
}
|
|
222
206
|
|
|
223
207
|
if (!storeTask.isInitialized) {
|
|
@@ -232,7 +216,7 @@ export class DependencyProcessor {
|
|
|
232
216
|
);
|
|
233
217
|
}
|
|
234
218
|
|
|
235
|
-
return (input) => {
|
|
219
|
+
return (input: any) => {
|
|
236
220
|
return this.taskRunner.run(
|
|
237
221
|
storeTask.task,
|
|
238
222
|
input,
|
|
@@ -245,7 +229,7 @@ export class DependencyProcessor {
|
|
|
245
229
|
// check if it exists in the store with the value
|
|
246
230
|
const storeResource = this.store.resources.get(object.id);
|
|
247
231
|
if (storeResource === undefined) {
|
|
248
|
-
throw Errors.dependencyNotFound(`Resource ${object.id}`);
|
|
232
|
+
throw Errors.dependencyNotFound(`Resource ${object.id.toString()}`);
|
|
249
233
|
}
|
|
250
234
|
|
|
251
235
|
const { resource, config } = storeResource;
|
|
@@ -256,11 +240,20 @@ export class DependencyProcessor {
|
|
|
256
240
|
storeResource.isInitialized = true;
|
|
257
241
|
|
|
258
242
|
// check if it has an initialisation function that provides the value
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
243
|
+
if (resource.init) {
|
|
244
|
+
const { value, context } =
|
|
245
|
+
await this.resourceInitializer.initializeResource(
|
|
246
|
+
resource,
|
|
247
|
+
config,
|
|
248
|
+
await this.extractDependencies(
|
|
249
|
+
resource.dependencies || {},
|
|
250
|
+
resource.id
|
|
251
|
+
)
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
storeResource.context = context;
|
|
255
|
+
storeResource.value = value;
|
|
256
|
+
}
|
|
264
257
|
}
|
|
265
258
|
|
|
266
259
|
return storeResource.value;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
EventHandlerType,
|
|
3
|
+
IEvent,
|
|
4
|
+
IEventDefinition,
|
|
5
|
+
IEventEmission,
|
|
6
|
+
} from "../defs";
|
|
2
7
|
import { Errors } from "../errors";
|
|
3
8
|
import { Logger } from "./Logger";
|
|
4
9
|
|
|
@@ -6,13 +11,13 @@ const HandlerOptionsDefaults = { order: 0 };
|
|
|
6
11
|
|
|
7
12
|
interface IListenerStorage {
|
|
8
13
|
order: number;
|
|
9
|
-
filter?: (event:
|
|
14
|
+
filter?: (event: IEventEmission<any>) => boolean;
|
|
10
15
|
handler: EventHandlerType;
|
|
11
16
|
}
|
|
12
17
|
|
|
13
18
|
export interface IEventHandlerOptions<T = any> {
|
|
14
19
|
order?: number;
|
|
15
|
-
filter?: (event:
|
|
20
|
+
filter?: (event: IEventEmission<T>) => boolean;
|
|
16
21
|
/**
|
|
17
22
|
* Represents the listener ID. Use this to avoid a listener calling himself.
|
|
18
23
|
*/
|
|
@@ -20,8 +25,11 @@ export interface IEventHandlerOptions<T = any> {
|
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
export class EventManager {
|
|
23
|
-
private listeners: Map<string, IListenerStorage[]> = new Map();
|
|
28
|
+
private listeners: Map<string | symbol, IListenerStorage[]> = new Map();
|
|
24
29
|
private globalListeners: IListenerStorage[] = [];
|
|
30
|
+
private cachedMergedListeners: Map<string | symbol, IListenerStorage[]> =
|
|
31
|
+
new Map();
|
|
32
|
+
private globalListenersCacheValid = true;
|
|
25
33
|
#isLocked = false;
|
|
26
34
|
|
|
27
35
|
get isLocked() {
|
|
@@ -57,18 +65,54 @@ export class EventManager {
|
|
|
57
65
|
return result;
|
|
58
66
|
}
|
|
59
67
|
|
|
68
|
+
private getCachedMergedListeners(
|
|
69
|
+
eventId: string | symbol
|
|
70
|
+
): IListenerStorage[] {
|
|
71
|
+
if (!this.globalListenersCacheValid) {
|
|
72
|
+
this.cachedMergedListeners.clear();
|
|
73
|
+
this.globalListenersCacheValid = true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let cached = this.cachedMergedListeners.get(eventId);
|
|
77
|
+
if (!cached) {
|
|
78
|
+
const eventListeners = this.listeners.get(eventId) || [];
|
|
79
|
+
if (eventListeners.length === 0 && this.globalListeners.length === 0) {
|
|
80
|
+
cached = [];
|
|
81
|
+
} else if (eventListeners.length === 0) {
|
|
82
|
+
cached = this.globalListeners;
|
|
83
|
+
} else if (this.globalListeners.length === 0) {
|
|
84
|
+
cached = eventListeners;
|
|
85
|
+
} else {
|
|
86
|
+
cached = this.mergeSortedListeners(
|
|
87
|
+
eventListeners,
|
|
88
|
+
this.globalListeners
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
this.cachedMergedListeners.set(eventId, cached);
|
|
92
|
+
}
|
|
93
|
+
return cached;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private invalidateCache(eventId?: string | symbol): void {
|
|
97
|
+
if (eventId) {
|
|
98
|
+
this.cachedMergedListeners.delete(eventId);
|
|
99
|
+
} else {
|
|
100
|
+
this.globalListenersCacheValid = false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
60
104
|
async emit<TInput>(
|
|
61
|
-
eventDefinition:
|
|
105
|
+
eventDefinition: IEvent<TInput>,
|
|
62
106
|
data: TInput,
|
|
63
|
-
source: string
|
|
107
|
+
source: string | symbol
|
|
64
108
|
): Promise<void> {
|
|
65
|
-
const
|
|
66
|
-
const allListeners = this.mergeSortedListeners(
|
|
67
|
-
eventListeners,
|
|
68
|
-
this.globalListeners
|
|
69
|
-
);
|
|
109
|
+
const allListeners = this.getCachedMergedListeners(eventDefinition.id);
|
|
70
110
|
|
|
71
|
-
|
|
111
|
+
if (allListeners.length === 0) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const event: IEventEmission = {
|
|
72
116
|
id: eventDefinition.id,
|
|
73
117
|
data,
|
|
74
118
|
timestamp: new Date(),
|
|
@@ -100,7 +144,7 @@ export class EventManager {
|
|
|
100
144
|
}
|
|
101
145
|
|
|
102
146
|
addListener<T>(
|
|
103
|
-
event:
|
|
147
|
+
event: IEvent<T> | Array<IEvent<T>>,
|
|
104
148
|
handler: EventHandlerType<T>,
|
|
105
149
|
options: IEventHandlerOptions<T> = HandlerOptionsDefaults
|
|
106
150
|
): void {
|
|
@@ -121,6 +165,7 @@ export class EventManager {
|
|
|
121
165
|
} else {
|
|
122
166
|
this.listeners.set(eventId, [newListener]);
|
|
123
167
|
}
|
|
168
|
+
this.invalidateCache(eventId);
|
|
124
169
|
}
|
|
125
170
|
}
|
|
126
171
|
|
|
@@ -135,5 +180,11 @@ export class EventManager {
|
|
|
135
180
|
filter: options.filter,
|
|
136
181
|
};
|
|
137
182
|
this.insertListener(this.globalListeners, newListener);
|
|
183
|
+
this.invalidateCache();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
hasListeners<T>(eventDefinition: IEvent<T>): boolean {
|
|
187
|
+
const eventListeners = this.listeners.get(eventDefinition.id) || [];
|
|
188
|
+
return eventListeners.length > 0 || this.globalListeners.length > 0;
|
|
138
189
|
}
|
|
139
190
|
}
|