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

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,5 +1,5 @@
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
 
@@ -11,7 +11,7 @@ npm install @travetto/worker
11
11
  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
12
 
13
13
  ## 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.
14
+ 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
15
 
16
16
  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
17
 
@@ -19,7 +19,7 @@ Below is a pool that will convert images on demand, while queuing as needed.
19
19
 
20
20
  **Code: Image processing queue, with a fixed batch/pool size**
21
21
  ```typescript
22
- import { ExecUtil, ExecutionState } from '@travetto/boot';
22
+ import { ExecUtil, ExecutionState } from '@travetto/base';
23
23
  import { Worker, WorkPool, IterableWorkSet, ManualAsyncIterator } from '@travetto/worker';
24
24
 
25
25
  class ImageProcessor implements Worker<string> {
@@ -46,7 +46,7 @@ class ImageProcessor implements Worker<string> {
46
46
  }
47
47
  }
48
48
 
49
- export class ImageCompressor extends WorkPool<string, ImageProcessor> {
49
+ export class ImageCompressor extends WorkPool<string> {
50
50
 
51
51
  pendingImages = new ManualAsyncIterator<string>();
52
52
 
@@ -68,14 +68,14 @@ Once a pool is constructed, it can be shutdown by calling the `.shutdown()` meth
68
68
 
69
69
  ## IPC Support
70
70
 
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.
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#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
72
 
73
73
  ### 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.
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#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
75
 
76
76
  **Code: Spawned Worker**
77
77
  ```typescript
78
- import { ExecutionState } from '@travetto/boot';
78
+ import { ExecutionState } from '@travetto/base';
79
79
 
80
80
  import { ParentCommChannel } from './comm/parent';
81
81
  import { Worker } from './pool';
@@ -112,17 +112,17 @@ export class WorkUtil {
112
112
  }
113
113
  ```
114
114
 
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:
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#L10)) and the input value. A simple example could look like:
116
116
 
117
117
  **Code: Spawning Pool**
118
118
  ```typescript
119
+ import { ExecUtil } from '@travetto/base';
119
120
  import { WorkPool, WorkUtil, IterableWorkSet } from '@travetto/worker';
120
- import { ExecUtil, PathUtil } from '@travetto/boot';
121
121
 
122
122
  export async function main(): Promise<void> {
123
123
  const pool = new WorkPool(() =>
124
- WorkUtil.spawnedWorker<{ data: string }, string>(
125
- () => ExecUtil.forkMain(PathUtil.resolveUnix(__dirname, 'spawned.ts')),
124
+ WorkUtil.spawnedWorker<{ data: string }, number>(
125
+ () => ExecUtil.spawn('trv', ['main', 'support/main.spawned.ts']),
126
126
  ch => ch.once('ready'), // Wait for child to indicate it is ready
127
127
  async (channel, inp) => {
128
128
  const res = channel.once('response'); // Register response listener
@@ -131,21 +131,20 @@ export async function main(): Promise<void> {
131
131
  const { data } = await res; // Get answer
132
132
  console.log('Request complete', { input: inp, output: data });
133
133
 
134
- if (!(inp + inp === data)) {
134
+ if (!(`${inp + inp}` === data)) {
135
135
  // Ensure the answer is double the input
136
136
  throw new Error('Did not get the double');
137
137
  }
138
138
  }
139
139
  )
140
140
  );
141
-
142
- await pool.process(new IterableWorkSet([1, 2, 3, 4, 5])).then(x => pool.shutdown());
141
+ await pool.process(new IterableWorkSet([1, 2, 3, 4, 5]));
143
142
  }
144
143
  ```
145
144
 
146
145
  **Code: Spawned Worker**
147
146
  ```typescript
148
- import * as timers from 'timers/promises';
147
+ import timers from 'timers/promises';
149
148
  import { ChildCommChannel } from '@travetto/worker';
150
149
 
151
150
  export async function main(): Promise<void> {
@@ -163,11 +162,12 @@ export async function main(): Promise<void> {
163
162
 
164
163
  **Terminal: Output**
165
164
  ```bash
166
- $ node @travetto/base/bin/main ./doc/spawner.ts
165
+ $ trv main ./support/main.spawner.ts
167
166
 
168
167
  Request complete { input: 1, output: 2 }
169
168
  Request complete { input: 2, output: 4 }
170
169
  Request complete { input: 3, output: 6 }
171
170
  Request complete { input: 4, output: 8 }
172
171
  Request complete { input: 5, output: 10 }
172
+ 
173
173
  ```
File without changes
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.4",
5
4
  "description": "Process management utilities, with a focus on inter-process communication",
6
5
  "keywords": [
7
6
  "exec",
@@ -17,18 +16,21 @@
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",
28
+ "@travetto/base": "^3.0.0-rc.4",
30
29
  "@types/generic-pool": "^3.1.11",
31
- "generic-pool": "^3.8.2"
30
+ "generic-pool": "^3.9.0"
31
+ },
32
+ "travetto": {
33
+ "displayName": "Worker"
32
34
  },
33
35
  "publishConfig": {
34
36
  "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';