@travetto/worker 3.0.0-rc.2 → 3.0.0-rc.21

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 CHANGED
@@ -1,17 +1,21 @@
1
1
  <!-- This file was generated by @travetto/doc and should not be modified directly -->
2
- <!-- Please modify https://github.com/travetto/travetto/tree/main/module/worker/doc.ts and execute "npx trv doc" to rebuild -->
2
+ <!-- Please modify https://github.com/travetto/travetto/tree/main/module/worker/DOC.ts and execute "npx trv doc" to rebuild -->
3
3
  # Worker
4
4
  ## Process management utilities, with a focus on inter-process communication
5
5
 
6
6
  **Install: @travetto/worker**
7
7
  ```bash
8
8
  npm install @travetto/worker
9
+
10
+ # or
11
+
12
+ yarn add @travetto/worker
9
13
  ```
10
14
 
11
15
  This module provides the necessary primitives for handling dependent workers. A worker can be an individual actor or could be a pool of workers. Node provides ipc (inter-process communication) functionality out of the box. This module builds upon that by providing enhanced event management, richer process management, as well as constructs for orchestrating a conversation between two processes.
12
16
 
13
17
  ## Execution Pools
14
- With respect to managing multiple executions, [WorkPool](https://github.com/travetto/travetto/tree/main/module/worker/src/pool.ts#L23) is provided to allow for concurrent operation, and processing of jobs concurrently. To manage the flow of jobs, there are various [WorkSet](https://github.com/travetto/travetto/tree/main/module/worker/src/input/types.ts#L4) implementation that allow for a wide range of use cases.
18
+ With respect to managing multiple executions, [WorkPool](https://github.com/travetto/travetto/tree/main/module/worker/src/pool.ts#L31) is provided to allow for concurrent operation, and processing of jobs concurrently. To manage the flow of jobs, there are various [WorkSet](https://github.com/travetto/travetto/tree/main/module/worker/src/input/types.ts#L4) implementation that allow for a wide range of use cases.
15
19
 
16
20
  The only provided [WorkSet](https://github.com/travetto/travetto/tree/main/module/worker/src/input/types.ts#L4) is the [IterableWorkSet](https://github.com/travetto/travetto/tree/main/module/worker/src/input/iterable.ts#L11) which supports all `Iterable` and `Iterator` sources. Additionally, the module provides [ManualAsyncIterator](https://github.com/travetto/travetto/tree/main/module/worker/src/input/async-iterator.ts#L6) which allows for manual control of iteration, which is useful for event driven work loads.
17
21
 
@@ -19,7 +23,7 @@ Below is a pool that will convert images on demand, while queuing as needed.
19
23
 
20
24
  **Code: Image processing queue, with a fixed batch/pool size**
21
25
  ```typescript
22
- import { ExecUtil, ExecutionState } from '@travetto/boot';
26
+ import { ExecUtil, ExecutionState } from '@travetto/base';
23
27
  import { Worker, WorkPool, IterableWorkSet, ManualAsyncIterator } from '@travetto/worker';
24
28
 
25
29
  class ImageProcessor implements Worker<string> {
@@ -46,7 +50,7 @@ class ImageProcessor implements Worker<string> {
46
50
  }
47
51
  }
48
52
 
49
- export class ImageCompressor extends WorkPool<string, ImageProcessor> {
53
+ export class ImageCompressor extends WorkPool<string> {
50
54
 
51
55
  pendingImages = new ManualAsyncIterator<string>();
52
56
 
@@ -68,14 +72,14 @@ Once a pool is constructed, it can be shutdown by calling the `.shutdown()` meth
68
72
 
69
73
  ## IPC Support
70
74
 
71
- Within the `comm` package, there is support for two primary communication elements: [ChildCommChannel](https://github.com/travetto/travetto/tree/main/module/worker/src/comm/child.ts#L6) and [ParentCommChannel](https://github.com/travetto/travetto/tree/main/module/worker/src/comm/parent.ts#L11). Usually [ParentCommChannel](https://github.com/travetto/travetto/tree/main/module/worker/src/comm/parent.ts#L11) indicates it is the owner of the sub process. [ChildCommChannel](https://github.com/travetto/travetto/tree/main/module/worker/src/comm/child.ts#L6) indicates that it has been created/spawned/forked by the parent and will communicate back to it's parent. This generally means that a [ParentCommChannel](https://github.com/travetto/travetto/tree/main/module/worker/src/comm/parent.ts#L11) can be destroyed (i.e. killing the subprocess) where a [ChildCommChannel](https://github.com/travetto/travetto/tree/main/module/worker/src/comm/child.ts#L6) can only exit the process, but the channel cannot be destroyed.
75
+ Within the `comm` package, there is support for two primary communication elements: [ChildCommChannel](https://github.com/travetto/travetto/tree/main/module/worker/src/comm/child.ts#L6) and [ParentCommChannel](https://github.com/travetto/travetto/tree/main/module/worker/src/comm/parent.ts#L10). Usually [ParentCommChannel](https://github.com/travetto/travetto/tree/main/module/worker/src/comm/parent.ts#L10) indicates it is the owner of the sub process. [ChildCommChannel](https://github.com/travetto/travetto/tree/main/module/worker/src/comm/child.ts#L6) indicates that it has been created/spawned/forked by the parent and will communicate back to it's parent. This generally means that a [ParentCommChannel](https://github.com/travetto/travetto/tree/main/module/worker/src/comm/parent.ts#L10) can be destroyed (i.e. killing the subprocess) where a [ChildCommChannel](https://github.com/travetto/travetto/tree/main/module/worker/src/comm/child.ts#L6) can only exit the process, but the channel cannot be destroyed.
72
76
 
73
77
  ### IPC as a Worker
74
- A common pattern is to want to model a sub process as a worker, to be a valid candidate in a [WorkPool](https://github.com/travetto/travetto/tree/main/module/worker/src/pool.ts#L23). The [WorkUtil](https://github.com/travetto/travetto/tree/main/module/worker/src/util.ts#L14) class provides a utility to facilitate this desire.
78
+ A common pattern is to want to model a sub process as a worker, to be a valid candidate in a [WorkPool](https://github.com/travetto/travetto/tree/main/module/worker/src/pool.ts#L31). The [WorkUtil](https://github.com/travetto/travetto/tree/main/module/worker/src/util.ts#L14) class provides a utility to facilitate this desire.
75
79
 
76
80
  **Code: Spawned Worker**
77
81
  ```typescript
78
- import { ExecutionState } from '@travetto/boot';
82
+ import { ExecutionState } from '@travetto/base';
79
83
 
80
84
  import { ParentCommChannel } from './comm/parent';
81
85
  import { Worker } from './pool';
@@ -112,17 +116,17 @@ export class WorkUtil {
112
116
  }
113
117
  ```
114
118
 
115
- When creating your work, via process spawning, you will need to provide the script (and any other features you would like in `SpawnConfig`). Additionally you must, at a minimum, provide functionality to run whenever an input element is up for grabs in the input source. This method will be provided the communication channel ([ParentCommChannel](https://github.com/travetto/travetto/tree/main/module/worker/src/comm/parent.ts#L11)) and the input value. A simple example could look like:
119
+ When creating your work, via process spawning, you will need to provide the script (and any other features you would like in `SpawnConfig`). Additionally you must, at a minimum, provide functionality to run whenever an input element is up for grabs in the input source. This method will be provided the communication channel ([ParentCommChannel](https://github.com/travetto/travetto/tree/main/module/worker/src/comm/parent.ts#L10)) and the input value. A simple example could look like:
116
120
 
117
121
  **Code: Spawning Pool**
118
122
  ```typescript
123
+ import { ExecUtil } from '@travetto/base';
119
124
  import { WorkPool, WorkUtil, IterableWorkSet } from '@travetto/worker';
120
- import { ExecUtil, PathUtil } from '@travetto/boot';
121
125
 
122
126
  export async function main(): Promise<void> {
123
127
  const pool = new WorkPool(() =>
124
- WorkUtil.spawnedWorker<{ data: string }, string>(
125
- () => ExecUtil.forkMain(PathUtil.resolveUnix(__dirname, 'spawned.ts')),
128
+ WorkUtil.spawnedWorker<{ data: string }, number>(
129
+ () => ExecUtil.spawn('trv', ['main', '@travetto/worker/doc/spawned.ts']),
126
130
  ch => ch.once('ready'), // Wait for child to indicate it is ready
127
131
  async (channel, inp) => {
128
132
  const res = channel.once('response'); // Register response listener
@@ -131,21 +135,20 @@ export async function main(): Promise<void> {
131
135
  const { data } = await res; // Get answer
132
136
  console.log('Request complete', { input: inp, output: data });
133
137
 
134
- if (!(inp + inp === data)) {
138
+ if (!(`${inp + inp}` === data)) {
135
139
  // Ensure the answer is double the input
136
140
  throw new Error('Did not get the double');
137
141
  }
138
142
  }
139
143
  )
140
144
  );
141
-
142
- await pool.process(new IterableWorkSet([1, 2, 3, 4, 5])).then(x => pool.shutdown());
145
+ await pool.process(new IterableWorkSet([1, 2, 3, 4, 5]));
143
146
  }
144
147
  ```
145
148
 
146
149
  **Code: Spawned Worker**
147
150
  ```typescript
148
- import * as timers from 'timers/promises';
151
+ import timers from 'timers/promises';
149
152
  import { ChildCommChannel } from '@travetto/worker';
150
153
 
151
154
  export async function main(): Promise<void> {
@@ -163,7 +166,7 @@ export async function main(): Promise<void> {
163
166
 
164
167
  **Terminal: Output**
165
168
  ```bash
166
- $ node @travetto/base/bin/main ./doc/spawner.ts
169
+ $ trv main doc/spawner.ts
167
170
 
168
171
  Request complete { input: 1, output: 2 }
169
172
  Request complete { input: 2, output: 4 }
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/worker",
3
- "displayName": "Worker",
4
- "version": "3.0.0-rc.2",
3
+ "version": "3.0.0-rc.21",
5
4
  "description": "Process management utilities, with a focus on inter-process communication",
6
5
  "keywords": [
7
6
  "exec",
@@ -17,18 +16,20 @@
17
16
  "name": "Travetto Framework"
18
17
  },
19
18
  "files": [
20
- "index.ts",
19
+ "__index__.ts",
21
20
  "src"
22
21
  ],
23
- "main": "index.ts",
22
+ "main": "__index__.ts",
24
23
  "repository": {
25
24
  "url": "https://github.com/travetto/travetto.git",
26
25
  "directory": "module/worker"
27
26
  },
28
27
  "dependencies": {
29
- "@travetto/base": "^3.0.0-rc.2",
30
- "@types/generic-pool": "^3.1.11",
31
- "generic-pool": "^3.8.2"
28
+ "@travetto/base": "^3.0.0-rc.21",
29
+ "generic-pool": "^3.9.0"
30
+ },
31
+ "travetto": {
32
+ "displayName": "Worker"
32
33
  },
33
34
  "publishConfig": {
34
35
  "access": "public"
@@ -1,7 +1,7 @@
1
1
  import { ChildProcess } from 'child_process';
2
2
  import { EventEmitter } from 'events';
3
3
 
4
- import { ExecUtil } from '@travetto/boot';
4
+ import { ExecUtil } from '@travetto/base';
5
5
 
6
6
  /**
7
7
  * Channel that represents communication between parent/child
@@ -1,7 +1,6 @@
1
1
  import { ChildProcess } from 'child_process';
2
2
 
3
- import { ExecutionState } from '@travetto/boot';
4
- import { ShutdownManager } from '@travetto/base';
3
+ import { ShutdownManager, ExecutionState } from '@travetto/base';
5
4
 
6
5
  import { ProcessCommChannel } from './channel';
7
6
 
@@ -14,7 +13,7 @@ export class ParentCommChannel<U = unknown> extends ProcessCommChannel<ChildProc
14
13
 
15
14
  constructor(state: ExecutionState) {
16
15
  super(state.process);
17
- ShutdownManager.onShutdown({ close: () => this.destroy() });
16
+ ShutdownManager.onShutdown(this, { close: () => this.destroy() });
18
17
  this.#complete = state.result
19
18
  .finally(() => { this.proc = undefined; });
20
19
  }
@@ -3,17 +3,24 @@ import { Util } from '@travetto/base';
3
3
  /**
4
4
  * Manual async iterator. Items are added manually, and consumed asynchronously
5
5
  */
6
- export class ManualAsyncIterator<X> implements AsyncIterator<X> {
6
+ export class ManualAsyncIterator<X> implements AsyncIterator<X>, AsyncIterable<X> {
7
7
 
8
8
  #queue: X[] = [];
9
9
  #done = false;
10
10
  #ready = Util.resolvablePromise();
11
+ #size: number;
11
12
 
12
13
  /**
13
14
  * Initial set of items
14
15
  */
15
16
  constructor(initial: Iterable<X> = []) {
16
17
  this.#queue.push(...initial);
18
+ this.#size = this.#queue.length;
19
+ }
20
+
21
+ // Allow for iteration
22
+ [Symbol.asyncIterator](): AsyncIterator<X> {
23
+ return this;
17
24
  }
18
25
 
19
26
  /**
@@ -38,6 +45,7 @@ export class ManualAsyncIterator<X> implements AsyncIterator<X> {
38
45
  } else {
39
46
  this.#queue.unshift(...item);
40
47
  }
48
+ this.#size += item.length;
41
49
  this.#ready.resolve();
42
50
  }
43
51
 
@@ -48,4 +56,11 @@ export class ManualAsyncIterator<X> implements AsyncIterator<X> {
48
56
  this.#done = true;
49
57
  this.#ready.resolve();
50
58
  }
59
+
60
+ /**
61
+ * Get size, will change as items are added
62
+ */
63
+ get size(): number {
64
+ return this.#size;
65
+ }
51
66
  }
@@ -13,6 +13,7 @@ export class IterableWorkSet<X> implements WorkSet<X> {
13
13
  #src: Itr<X>;
14
14
  #ondeck?: X;
15
15
  #done = false;
16
+ #size?: number;
16
17
 
17
18
  constructor(src: Iterable<X> | AsyncIterable<X> | (() => Generator<X>) | (() => AsyncGenerator<X>) | Itr<X>) {
18
19
  if ('next' in src) {
@@ -26,6 +27,11 @@ export class IterableWorkSet<X> implements WorkSet<X> {
26
27
  this.#src = src();
27
28
  }
28
29
  }
30
+ if (Array.isArray(src)) {
31
+ this.#size = src.length;
32
+ } else if (src instanceof Set) {
33
+ this.#size = src.size;
34
+ }
29
35
  }
30
36
 
31
37
  /**
@@ -57,4 +63,11 @@ export class IterableWorkSet<X> implements WorkSet<X> {
57
63
  this.#ondeck = undefined;
58
64
  return out;
59
65
  }
66
+
67
+ /**
68
+ * Get size, if defined
69
+ */
70
+ get size(): number | undefined {
71
+ return this.#size;
72
+ }
60
73
  }
@@ -10,4 +10,8 @@ export interface WorkSet<X> {
10
10
  * Get next item
11
11
  */
12
12
  next(): X | Promise<X>;
13
+ /**
14
+ * Total size of work set
15
+ */
16
+ size?: number;
13
17
  }
package/src/pool.ts CHANGED
@@ -1,9 +1,10 @@
1
- import * as os from 'os';
2
- import * as gp from 'generic-pool';
1
+ import os from 'os';
2
+ import gp from 'generic-pool';
3
3
 
4
- import { ShutdownManager, Util } from '@travetto/base';
4
+ import { GlobalEnv, ShutdownManager, TimeUtil } from '@travetto/base';
5
5
 
6
6
  import { WorkSet } from './input/types';
7
+ import { ManualAsyncIterator } from '../src/input/async-iterator';
7
8
 
8
9
  /**
9
10
  * Worker definition
@@ -17,17 +18,24 @@ export interface Worker<X> {
17
18
  release?(): unknown;
18
19
  }
19
20
 
21
+ type WorkPoolProcessConfig<X> = {
22
+ shutdownOnComplete?: boolean;
23
+ onComplete?: (ev: WorkCompletionEvent<X>) => (void | Promise<void>);
24
+ };
25
+
26
+ type WorkCompletionEvent<X> = { idx: number, total?: number, value: X };
27
+
20
28
  /**
21
29
  * Work pool support
22
30
  */
23
- export class WorkPool<X, T extends Worker<X>> {
31
+ export class WorkPool<X> {
24
32
 
25
33
  static DEFAULT_SIZE = Math.min(os.cpus().length - 1, 4);
26
34
 
27
35
  /**
28
36
  * Generic-pool pool
29
37
  */
30
- #pool: gp.Pool<T>;
38
+ #pool: gp.Pool<Worker<X>>;
31
39
  /**
32
40
  * Number of acquisitions in process
33
41
  */
@@ -42,12 +50,22 @@ export class WorkPool<X, T extends Worker<X>> {
42
50
  */
43
51
  #createErrors = 0;
44
52
 
53
+ /**
54
+ * Are we tracing
55
+ */
56
+ #trace: boolean;
57
+
58
+ /**
59
+ * Cleanup for shutdown
60
+ */
61
+ #shutdownCleanup?: () => void;
62
+
45
63
  /**
46
64
  *
47
65
  * @param getWorker Produces a new worker for the pool
48
66
  * @param opts Pool options
49
67
  */
50
- constructor(getWorker: () => Promise<T> | T, opts?: gp.Options) {
68
+ constructor(getWorker: () => Promise<Worker<X>> | Worker<X>, opts?: gp.Options) {
51
69
  const args = {
52
70
  max: WorkPool.DEFAULT_SIZE,
53
71
  min: 1,
@@ -59,16 +77,21 @@ export class WorkPool<X, T extends Worker<X>> {
59
77
  this.#pool = gp.createPool({
60
78
  create: () => this.#createAndTrack(getWorker, args),
61
79
  destroy: x => this.destroy(x),
62
- validate: async (x: T) => x.active
80
+ validate: async (x: Worker<X>) => x.active
63
81
  }, args);
64
82
 
65
- ShutdownManager.onShutdown(`worker.pool.${this.constructor.name}`, () => this.shutdown());
83
+ this.#shutdownCleanup = ShutdownManager.onShutdown(`worker.pool.${this.constructor.name}`, () => {
84
+ this.#shutdownCleanup = undefined;
85
+ this.shutdown();
86
+ });
87
+
88
+ this.#trace = !!GlobalEnv.debug?.includes('@travetto/worker');
66
89
  }
67
90
 
68
91
  /**
69
92
  * Creates and tracks new worker
70
93
  */
71
- async #createAndTrack(getWorker: () => Promise<T> | T, opts: gp.Options): Promise<T> {
94
+ async #createAndTrack(getWorker: () => Promise<Worker<X>> | Worker<X>, opts: gp.Options): Promise<Worker<X>> {
72
95
  try {
73
96
  this.#pendingAcquires += 1;
74
97
  const res = await getWorker();
@@ -83,7 +106,7 @@ export class WorkPool<X, T extends Worker<X>> {
83
106
  } catch (err) {
84
107
  if (this.#createErrors++ > opts.max!) { // If error count is bigger than pool size, we broke
85
108
  console.error('Failed in creating pool', { error: err });
86
- process.exit(1);
109
+ await ShutdownManager.exit(1);
87
110
  }
88
111
  throw err;
89
112
  } finally {
@@ -94,23 +117,25 @@ export class WorkPool<X, T extends Worker<X>> {
94
117
  /**
95
118
  * Destroy the worker
96
119
  */
97
- async destroy(worker: T): Promise<void> {
98
- console.debug('Destroying', { pid: process.pid, worker: worker.id });
120
+ async destroy(worker: Worker<X>): Promise<void> {
121
+ if (this.#trace) {
122
+ console.debug('Destroying', { pid: process.pid, worker: worker.id });
123
+ }
99
124
  return worker.destroy();
100
125
  }
101
126
 
102
127
  /**
103
128
  * Free worker on completion
104
129
  */
105
- async release(worker: T): Promise<void> {
106
- console.debug('Releasing', { pid: process.pid, worker: worker.id });
130
+ async release(worker: Worker<X>): Promise<void> {
131
+ if (this.#trace) {
132
+ console.debug('Releasing', { pid: process.pid, worker: worker.id });
133
+ }
107
134
  try {
108
135
  if (worker.active) {
109
- if (worker.release) {
110
- try {
111
- await worker.release();
112
- } catch { }
113
- }
136
+ try {
137
+ await worker.release?.();
138
+ } catch { }
114
139
  await this.#pool.release(worker);
115
140
  } else {
116
141
  await this.#pool.destroy(worker);
@@ -121,36 +146,63 @@ export class WorkPool<X, T extends Worker<X>> {
121
146
  /**
122
147
  * Process a given input source
123
148
  */
124
- async process(src: WorkSet<X>): Promise<void> {
149
+ async process(src: WorkSet<X>, cfg: WorkPoolProcessConfig<X> = {}): Promise<void> {
125
150
  const pending = new Set<Promise<unknown>>();
151
+ let count = 0;
152
+
153
+ if (src.size && cfg.onComplete) {
154
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
155
+ cfg.onComplete({ value: undefined as X, idx: 0, total: src.size });
156
+ }
126
157
 
127
158
  while (await src.hasNext()) {
128
159
  const worker = (await this.#pool.acquire())!;
129
- console.debug('Acquired', { pid: process.pid, worker: worker.id });
160
+ if (this.#trace) {
161
+ console.debug('Acquired', { pid: process.pid, worker: worker.id });
162
+ }
130
163
  const nextInput = await src.next();
131
164
 
132
165
  const completion = worker.execute(nextInput)
133
166
  .catch(err => this.#errors.push(err)) // Catch error
134
- .finally(() => this.release(worker));
167
+ .finally(() => this.release(worker))
168
+ .finally(() => cfg.onComplete?.({ value: nextInput, idx: count += 1, total: src.size }));
135
169
 
136
170
  completion.finally(() => pending.delete(completion));
137
171
 
138
172
  pending.add(completion);
139
173
  }
140
174
 
141
- await Promise.all(Array.from(pending));
175
+ try {
176
+ await Promise.all(Array.from(pending));
142
177
 
143
- if (this.#errors.length) {
144
- throw this.#errors[0];
178
+ if (this.#errors.length) {
179
+ throw this.#errors[0];
180
+ }
181
+ } finally {
182
+ if (cfg.shutdownOnComplete !== false) {
183
+ await this.shutdown();
184
+ }
145
185
  }
146
186
  }
147
187
 
188
+ /**
189
+ * Process a given input source as an async iterable, emitting on completion
190
+ */
191
+ iterateProcess(src: WorkSet<X>, shutdownOnComplete?: boolean): AsyncIterable<WorkCompletionEvent<X>> {
192
+ const itr = new ManualAsyncIterator<WorkCompletionEvent<X>>();
193
+ const res = this.process(src, { onComplete: ev => itr.add(ev), shutdownOnComplete });
194
+ res.finally(() => itr.close());
195
+ return itr;
196
+ }
197
+
148
198
  /**
149
199
  * Shutdown pool
150
200
  */
151
201
  async shutdown(): Promise<void> {
202
+ this.#shutdownCleanup?.();
203
+
152
204
  while (this.#pendingAcquires) {
153
- await Util.wait(10);
205
+ await TimeUtil.wait(10);
154
206
  }
155
207
  await this.#pool.drain();
156
208
  await this.#pool.clear();
@@ -1,4 +1,7 @@
1
- import { Util, ShutdownManager, TimeSpan } from '@travetto/base';
1
+ import { setTimeout } from 'timers/promises';
2
+
3
+ import { ShutdownManager, TimeSpan, Util } from '@travetto/base';
4
+
2
5
  import { Timeout } from './timeout';
3
6
 
4
7
  function canCancel(o: unknown): o is { cancel(): unknown } {
@@ -10,6 +13,23 @@ function canCancel(o: unknown): o is { cancel(): unknown } {
10
13
  * Build an execution barrier to handle various limitations
11
14
  */
12
15
  export class Barrier {
16
+ /**
17
+ * Listen for an unhandled event, as a promise
18
+ */
19
+ static listenForUnhandled(): Promise<never> & { cancel: () => void } {
20
+ const uncaught = Util.resolvablePromise<never>();
21
+ const uncaughtWithCancel: typeof uncaught & { cancel?: () => void } = uncaught;
22
+ const cancel = ShutdownManager.onUnhandled(err => { setTimeout(1).then(() => uncaught.reject(err)); return true; }, 0);
23
+ uncaughtWithCancel.cancel = (): void => {
24
+ cancel(); // Remove the handler
25
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
26
+ uncaughtWithCancel.resolve(undefined as never); // Close the promise
27
+ };
28
+
29
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
30
+ return uncaughtWithCancel as (Promise<never> & { cancel: () => void });
31
+ }
32
+
13
33
  #support: string[] = [];
14
34
  #barriers = new Map<string, Promise<unknown>>([]);
15
35
 
@@ -21,7 +41,7 @@ export class Barrier {
21
41
  this.add(new Timeout(timeout).wait(), true);
22
42
  }
23
43
  if (unhandled) {
24
- this.add(ShutdownManager.listenForUnhandled());
44
+ this.add(Barrier.listenForUnhandled());
25
45
  }
26
46
  }
27
47
 
@@ -1,4 +1,4 @@
1
- import { TimeSpan, Util } from '@travetto/base';
1
+ import { TimeSpan, TimeUtil, Util } from '@travetto/base';
2
2
  import { ExecutionError } from './error';
3
3
 
4
4
  /**
@@ -12,7 +12,7 @@ export class Timeout extends ExecutionError {
12
12
 
13
13
  constructor(duration: number | TimeSpan, op: string = 'Operation') {
14
14
  super(`${op} timed out after ${duration}${typeof duration === 'number' ? 'ms' : ''}`);
15
- this.#duration = Util.timeToMs(duration);
15
+ this.#duration = TimeUtil.timeToMs(duration);
16
16
  }
17
17
 
18
18
  /**
package/src/util.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ExecutionState } from '@travetto/boot';
1
+ import { ExecutionState } from '@travetto/base';
2
2
 
3
3
  import { ParentCommChannel } from './comm/parent';
4
4
  import { Worker } from './pool';
File without changes