@travetto/worker 2.1.3 → 2.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  <!-- This file was generated by @travetto/doc and should not be modified directly -->
2
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
- ## Process management utilties, with a focus on inter-process communication
4
+ ## Process management utilities, with a focus on inter-process communication
5
5
 
6
6
  **Install: @travetto/worker**
7
7
  ```bash
@@ -26,21 +26,21 @@ class ImageProcessor implements Worker<string> {
26
26
  active = false;
27
27
  proc: ExecutionState;
28
28
 
29
- get id() {
29
+ get id(): number | undefined {
30
30
  return this.proc.process.pid;
31
31
  }
32
32
 
33
- async destroy() {
33
+ async destroy(): Promise<void> {
34
34
  this.proc.process.kill();
35
35
  }
36
36
 
37
- async execute(path: string) {
37
+ async execute(path: string): Promise<void> {
38
38
  this.active = true;
39
39
  try {
40
40
  this.proc = ExecUtil.spawn('convert images', [path]);
41
41
  await this.proc;
42
- } catch (e) {
43
-
42
+ } catch {
43
+ // Do nothing
44
44
  }
45
45
  this.active = false;
46
46
  }
@@ -54,11 +54,11 @@ export class ImageCompressor extends WorkPool<string, ImageProcessor> {
54
54
  super(async () => new ImageProcessor());
55
55
  }
56
56
 
57
- begin() {
57
+ begin(): void {
58
58
  this.process(new IterableWorkSet(this.pendingImages));
59
59
  }
60
60
 
61
- convert(...images: string[]) {
61
+ convert(...images: string[]): void {
62
62
  this.pendingImages.add(images);
63
63
  }
64
64
  }
@@ -83,7 +83,7 @@ import { Worker } from './pool';
83
83
  type Simple<V> = (ch: ParentCommChannel<V>) => Promise<unknown | void>;
84
84
  type Param<V, X> = (ch: ParentCommChannel<V>, input: X) => Promise<unknown | void>;
85
85
 
86
- const empty = async () => { };
86
+ const empty = async (): Promise<void> => { };
87
87
 
88
88
  /**
89
89
  * Spawned worker
@@ -99,11 +99,11 @@ export class WorkUtil {
99
99
  destroy: Simple<V> = empty): Worker<X> {
100
100
  const channel = new ParentCommChannel<V>(worker());
101
101
  return {
102
- get id() { return channel.id; },
103
- get active() { return channel.active; },
102
+ get id(): number | undefined { return channel.id; },
103
+ get active(): boolean { return channel.active; },
104
104
  init: () => init(channel),
105
105
  execute: inp => execute(channel, inp),
106
- async destroy() {
106
+ async destroy(): Promise<void> {
107
107
  await destroy(channel);
108
108
  await channel.destroy();
109
109
  },
@@ -119,7 +119,7 @@ When creating your work, via process spawning, you will need to provide the scri
119
119
  import { WorkPool, WorkUtil, IterableWorkSet } from '@travetto/worker';
120
120
  import { ExecUtil, PathUtil } from '@travetto/boot';
121
121
 
122
- export function main() {
122
+ export async function main(): Promise<void> {
123
123
  const pool = new WorkPool(() =>
124
124
  WorkUtil.spawnedWorker<{ data: string }, string>(
125
125
  () => ExecUtil.forkMain(PathUtil.resolveUnix(__dirname, 'spawned.ts')),
@@ -139,7 +139,7 @@ export function main() {
139
139
  )
140
140
  );
141
141
 
142
- return pool.process(new IterableWorkSet([1, 2, 3, 4, 5])).then(x => pool.shutdown());
142
+ await pool.process(new IterableWorkSet([1, 2, 3, 4, 5])).then(x => pool.shutdown());
143
143
  }
144
144
  ```
145
145
 
@@ -147,7 +147,7 @@ export function main() {
147
147
  ```typescript
148
148
  import { ChildCommChannel } from '@travetto/worker';
149
149
 
150
- export async function main() {
150
+ export async function main(): Promise<void> {
151
151
  const exec = new ChildCommChannel<{ data: string }>();
152
152
 
153
153
  exec.on('request', data =>
@@ -155,7 +155,7 @@ export async function main() {
155
155
 
156
156
  exec.send('ready'); // Indicate the child is ready to receive requests
157
157
 
158
- const heartbeat = () => setTimeout(heartbeat, 5000); // Keep-alive
158
+ const heartbeat = (): void => { setTimeout(heartbeat, 5000); }; // Keep-alive
159
159
  heartbeat();
160
160
  }
161
161
  ```
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@travetto/worker",
3
3
  "displayName": "Worker",
4
- "version": "2.1.3",
5
- "description": "Process management utilties, with a focus on inter-process communication",
4
+ "version": "2.2.0",
5
+ "description": "Process management utilities, with a focus on inter-process communication",
6
6
  "keywords": [
7
7
  "exec",
8
8
  "child-process",
@@ -26,7 +26,7 @@
26
26
  "directory": "module/worker"
27
27
  },
28
28
  "dependencies": {
29
- "@travetto/base": "^2.1.3",
29
+ "@travetto/base": "^2.2.0",
30
30
  "@types/generic-pool": "^3.1.11",
31
31
  "generic-pool": "^3.8.2"
32
32
  },
@@ -17,17 +17,17 @@ export class ProcessCommChannel<T extends NodeJS.Process | ChildProcess, V = unk
17
17
  this.#proc.on('message', this.#handleMessage.bind(this));
18
18
  }
19
19
 
20
- get #parentId() {
20
+ get #parentId(): number {
21
21
  return process.pid;
22
22
  }
23
23
 
24
- #handleMessage(ev: { type: string }) {
24
+ #handleMessage(ev: { type: string }): void {
25
25
  console.debug('Received', { pid: this.#parentId, id: this.id, type: ev.type });
26
26
  this.#emitter.emit(ev.type, ev);
27
27
  this.#emitter.emit('*', ev);
28
28
  }
29
29
 
30
- get proc() {
30
+ get proc(): T | undefined {
31
31
  return this.#proc;
32
32
  }
33
33
 
@@ -38,21 +38,21 @@ export class ProcessCommChannel<T extends NodeJS.Process | ChildProcess, V = unk
38
38
  /**
39
39
  * Gets channel unique identifier
40
40
  */
41
- get id() {
41
+ get id(): number | undefined {
42
42
  return this.#proc && this.#proc.pid;
43
43
  }
44
44
 
45
45
  /**
46
46
  * Determines if channel is active
47
47
  */
48
- get active() {
48
+ get active(): boolean {
49
49
  return !!this.#proc;
50
50
  }
51
51
 
52
52
  /**
53
53
  * Send data to the parent
54
54
  */
55
- send(eventType: string, data?: Record<string, unknown>) {
55
+ send(eventType: string, data?: Record<string, unknown>): void {
56
56
  console.debug('Sending', { pid: this.#parentId, id: this.id, eventType });
57
57
  if (!this.#proc) {
58
58
  throw new Error('this.proc was not defined');
@@ -66,7 +66,7 @@ export class ProcessCommChannel<T extends NodeJS.Process | ChildProcess, V = unk
66
66
  /**
67
67
  * Listen for a specific message type
68
68
  */
69
- on(eventType: string, callback: (e: U) => unknown | void) {
69
+ on(eventType: string, callback: (e: U) => unknown | void): () => void {
70
70
  this.#emitter.on(eventType, callback);
71
71
  return () => this.off(eventType, callback);
72
72
  }
@@ -74,21 +74,21 @@ export class ProcessCommChannel<T extends NodeJS.Process | ChildProcess, V = unk
74
74
  /**
75
75
  * Remove event listener
76
76
  */
77
- off(eventType: string, callback: (e: U) => unknown | void) {
77
+ off(eventType: string, callback: (e: U) => unknown | void): void {
78
78
  this.#emitter.off(eventType, callback);
79
79
  }
80
80
 
81
81
  /**
82
82
  * Listen for a specific message type, once
83
83
  */
84
- once(eventType: string) {
84
+ once(eventType: string): Promise<U> {
85
85
  return new Promise<U>(res => this.#emitter.once(eventType, res));
86
86
  }
87
87
 
88
88
  /**
89
89
  * Destroy self
90
90
  */
91
- async destroy() {
91
+ async destroy(): Promise<void> {
92
92
  if (this.#proc) {
93
93
  console.debug('Killing', { pid: this.#parentId, id: this.id });
94
94
  if (this.#proc !== process) {
@@ -102,7 +102,7 @@ export class ProcessCommChannel<T extends NodeJS.Process | ChildProcess, V = unk
102
102
  /**
103
103
  * Remove all listeners, but do not destroy
104
104
  */
105
- release() {
105
+ release(): void {
106
106
  console.debug('Released', { pid: this.#parentId, id: this.id });
107
107
  this.#emitter.removeAllListeners();
108
108
  }
@@ -22,7 +22,7 @@ export class ParentCommChannel<U = unknown> extends ProcessCommChannel<ChildProc
22
22
  /**
23
23
  * Kill self and child
24
24
  */
25
- override async destroy() {
25
+ override async destroy(): Promise<void> {
26
26
  const res = super.destroy();
27
27
  await this.#complete;
28
28
  return await res;
@@ -19,7 +19,7 @@ export class ManualAsyncIterator<X> implements AsyncIterator<X> {
19
19
  /**
20
20
  * Wait for next event to fire
21
21
  */
22
- async next() {
22
+ async next(): Promise<IteratorResult<X>> {
23
23
  if (!this.#done && !this.#queue.length) {
24
24
  await this.#ready;
25
25
  this.#ready = Util.resolvablePromise();
@@ -31,7 +31,7 @@ export class ManualAsyncIterator<X> implements AsyncIterator<X> {
31
31
  * Queue next event to fire
32
32
  * @param {boolean} immediate Determines if item(s) should be append or prepended to the queue
33
33
  */
34
- add(item: X | X[], immediate = false) {
34
+ add(item: X | X[], immediate = false): void {
35
35
  item = Array.isArray(item) ? item : [item];
36
36
  if (!immediate) {
37
37
  this.#queue.push(...item);
@@ -44,7 +44,7 @@ export class ManualAsyncIterator<X> implements AsyncIterator<X> {
44
44
  /**
45
45
  * Close the iterator
46
46
  */
47
- close() {
47
+ close(): void {
48
48
  this.#done = true;
49
49
  this.#ready.resolve();
50
50
  }
@@ -2,8 +2,8 @@ import { WorkSet } from './types';
2
2
 
3
3
  type Itr<T> = Iterator<T> | AsyncIterator<T>;
4
4
 
5
- const hasAsyncItr = (o: unknown): o is AsyncIterable<unknown> => !!o && Symbol.asyncIterator in (o as object);
6
- const hasItr = (o: unknown): o is Iterable<unknown> => !!o && Symbol.iterator in (o as object);
5
+ const hasAsyncItr = (o: unknown): o is AsyncIterable<unknown> => !!o && typeof o === 'object' && Symbol.asyncIterator in o;
6
+ const hasItr = (o: unknown): o is Iterable<unknown> => !!o && typeof o === 'object' && Symbol.iterator in o;
7
7
 
8
8
  /**
9
9
  * Basic input source given an iterable input
@@ -31,7 +31,7 @@ export class IterableWorkSet<X> implements WorkSet<X> {
31
31
  /**
32
32
  * Fetch next item from the iterable
33
33
  */
34
- async #primeNext() {
34
+ async #primeNext(): Promise<void> {
35
35
  const res = await this.#src.next();
36
36
  this.#done = !!res.done;
37
37
  this.#ondeck = res.value;
@@ -40,7 +40,7 @@ export class IterableWorkSet<X> implements WorkSet<X> {
40
40
  /**
41
41
  * Determine if the iterable has more data
42
42
  */
43
- async hasNext() {
43
+ async hasNext(): Promise<boolean> {
44
44
  if (this.#ondeck === undefined) {
45
45
  await this.#primeNext();
46
46
  }
@@ -50,7 +50,7 @@ export class IterableWorkSet<X> implements WorkSet<X> {
50
50
  /**
51
51
  * Fetch next item
52
52
  */
53
- async next() {
53
+ async next(): Promise<X> {
54
54
  await this.hasNext();
55
55
 
56
56
  const out = this.#ondeck!;
package/src/pool.ts CHANGED
@@ -68,7 +68,7 @@ export class WorkPool<X, T extends Worker<X>> {
68
68
  /**
69
69
  * Creates and tracks new worker
70
70
  */
71
- async #createAndTrack(getWorker: () => Promise<T> | T, opts: gp.Options) {
71
+ async #createAndTrack(getWorker: () => Promise<T> | T, opts: gp.Options): Promise<T> {
72
72
  try {
73
73
  this.#pendingAcquires += 1;
74
74
  const res = await getWorker();
@@ -80,12 +80,12 @@ export class WorkPool<X, T extends Worker<X>> {
80
80
  this.#createErrors = 0; // Reset errors on success
81
81
 
82
82
  return res;
83
- } catch (e) {
83
+ } catch (err) {
84
84
  if (this.#createErrors++ > opts.max!) { // If error count is bigger than pool size, we broke
85
- console.error('Failed in creating pool', { error: e });
85
+ console.error('Failed in creating pool', { error: err });
86
86
  process.exit(1);
87
87
  }
88
- throw e;
88
+ throw err;
89
89
  } finally {
90
90
  this.#pendingAcquires -= 1;
91
91
  }
@@ -94,7 +94,7 @@ export class WorkPool<X, T extends Worker<X>> {
94
94
  /**
95
95
  * Destroy the worker
96
96
  */
97
- async destroy(worker: T) {
97
+ async destroy(worker: T): Promise<void> {
98
98
  console.debug('Destroying', { pid: process.pid, worker: worker.id });
99
99
  return worker.destroy();
100
100
  }
@@ -102,7 +102,7 @@ export class WorkPool<X, T extends Worker<X>> {
102
102
  /**
103
103
  * Free worker on completion
104
104
  */
105
- async release(worker: T) {
105
+ async release(worker: T): Promise<void> {
106
106
  console.debug('Releasing', { pid: process.pid, worker: worker.id });
107
107
  try {
108
108
  if (worker.active) {
@@ -121,7 +121,7 @@ export class WorkPool<X, T extends Worker<X>> {
121
121
  /**
122
122
  * Process a given input source
123
123
  */
124
- async process(src: WorkSet<X>) {
124
+ async process(src: WorkSet<X>): Promise<void> {
125
125
  const pending = new Set<Promise<unknown>>();
126
126
 
127
127
  while (await src.hasNext()) {
@@ -148,7 +148,7 @@ export class WorkPool<X, T extends Worker<X>> {
148
148
  /**
149
149
  * Shutdown pool
150
150
  */
151
- async shutdown() {
151
+ async shutdown(): Promise<void> {
152
152
  while (this.#pendingAcquires) {
153
153
  await Util.wait(10);
154
154
  }
@@ -2,6 +2,7 @@ import { Util, ShutdownManager, TimeSpan } from '@travetto/base';
2
2
  import { Timeout } from './timeout';
3
3
 
4
4
  function canCancel(o: unknown): o is { cancel(): unknown } {
5
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
5
6
  return !!o && 'cancel' in (o as object);
6
7
  }
7
8
 
@@ -9,7 +10,7 @@ function canCancel(o: unknown): o is { cancel(): unknown } {
9
10
  * Build an execution barrier to handle various limitations
10
11
  */
11
12
  export class Barrier {
12
- #support = [] as string[];
13
+ #support: string[] = [];
13
14
  #barriers = new Map<string, Promise<unknown>>([]);
14
15
 
15
16
  constructor(
@@ -27,7 +28,7 @@ export class Barrier {
27
28
  /**
28
29
  * Add a new barrier
29
30
  */
30
- add(p: (() => Promise<unknown>) | Promise<unknown>, support = false) {
31
+ add(p: (() => Promise<unknown>) | Promise<unknown>, support = false): this {
31
32
  if (!('then' in p)) {
32
33
  p = p();
33
34
  }
@@ -49,7 +50,7 @@ export class Barrier {
49
50
  /**
50
51
  * Clean up, and cancel all cancellable barriers
51
52
  */
52
- cleanup() {
53
+ cleanup(): void {
53
54
  for (const k of this.#support) {
54
55
  const el = this.#barriers.get(k);
55
56
  if (canCancel(el)) {
@@ -63,11 +64,11 @@ export class Barrier {
63
64
  * Wait for all barriers to clear out
64
65
  */
65
66
  async wait(): Promise<Error | undefined> {
66
- let err: Error | undefined;
67
+ let capturedError: Error | undefined;
67
68
  // Wait for all barriers to be satisfied
68
69
  while (this.#barriers.size) {
69
- await Promise.race(this.#barriers.values()).catch(e => err ??= e);
70
+ await Promise.race(this.#barriers.values()).catch(err => capturedError ??= err);
70
71
  }
71
- return err;
72
+ return capturedError;
72
73
  }
73
74
  }
@@ -18,7 +18,7 @@ export class Timeout extends ExecutionError {
18
18
  /**
19
19
  * Stop timeout from firing
20
20
  */
21
- cancel() {
21
+ cancel(): void {
22
22
  if (this.#id) {
23
23
  clearTimeout(this.#id);
24
24
  this.#promise.resolve();
@@ -29,7 +29,7 @@ export class Timeout extends ExecutionError {
29
29
  /**
30
30
  * Wait for timeout as a promise
31
31
  */
32
- wait() {
32
+ wait(): Promise<void> {
33
33
  if (!this.#id) {
34
34
  this.#id = setTimeout(() => this.#promise.reject(this), this.#duration);
35
35
  this.#id.unref();
package/src/util.ts CHANGED
@@ -6,7 +6,7 @@ import { Worker } from './pool';
6
6
  type Simple<V> = (ch: ParentCommChannel<V>) => Promise<unknown | void>;
7
7
  type Param<V, X> = (ch: ParentCommChannel<V>, input: X) => Promise<unknown | void>;
8
8
 
9
- const empty = async () => { };
9
+ const empty = async (): Promise<void> => { };
10
10
 
11
11
  /**
12
12
  * Spawned worker
@@ -22,11 +22,11 @@ export class WorkUtil {
22
22
  destroy: Simple<V> = empty): Worker<X> {
23
23
  const channel = new ParentCommChannel<V>(worker());
24
24
  return {
25
- get id() { return channel.id; },
26
- get active() { return channel.active; },
25
+ get id(): number | undefined { return channel.id; },
26
+ get active(): boolean { return channel.active; },
27
27
  init: () => init(channel),
28
28
  execute: inp => execute(channel, inp),
29
- async destroy() {
29
+ async destroy(): Promise<void> {
30
30
  await destroy(channel);
31
31
  await channel.destroy();
32
32
  },