1 import { isMainThread
, parentPort
} from
'worker_threads'
3 import { AsyncResource
} from
'async_hooks'
5 export interface ThreadWorkerOptions
{
7 * Max time to wait tasks to work on (in ms), after this period the new worker threads will die.
11 maxInactiveTime
?: number
13 * `true` if your function contains async pieces, else `false`.
21 * An example worker that will be always alive, you just need to **extend** this class if you want a static pool.
23 * When this worker is inactive for more than 1 minute, it will send this info to the main thread,
24 * if you are using DynamicThreadPool, the workers created after will be killed, the min num of thread will be guaranteed.
26 * @author [Alessandro Pio Ardizio](https://github.com/pioardi)
29 // eslint-disable-next-line @typescript-eslint/no-explicit-any
30 export class ThreadWorker
<Data
= any, Response
= any> extends AsyncResource
{
31 protected readonly maxInactiveTime
: number
32 protected readonly async: boolean
33 protected lastTask
: number
34 protected readonly interval
?: NodeJS
.Timeout
35 protected parent?: MessagePort
38 fn
: (data
: Data
) => Response
,
39 public readonly opts
: ThreadWorkerOptions
= {}
41 super('worker-thread-pool:pioardi')
43 this.maxInactiveTime
= this.opts
.maxInactiveTime
?? 1000 * 60
44 this.async = !!this.opts
.async
45 this.lastTask
= Date.now()
46 if (!fn
) throw new Error('Fn parameter is mandatory')
47 // keep the worker active
49 this.interval
= setInterval(
50 this.checkAlive
.bind(this),
51 this.maxInactiveTime
/ 2
53 this.checkAlive
.bind(this)()
63 if (value
?.data
&& value
.id
) {
64 // here you will receive messages
65 // console.log('This is the main thread ' + isMainThread)
67 this.runInAsyncScope(this.runAsync
.bind(this), this, fn
, value
)
69 this.runInAsyncScope(this.run
.bind(this), this, fn
, value
)
71 } else if (value
.parent) {
72 // save the port to communicate with the main thread
73 // this will be received once
74 this.parent = value
.parent
75 } else if (value
.kill
) {
76 // here is time to kill this thread, just clearing the interval
77 if (this.interval
) clearInterval(this.interval
)
84 protected checkAlive (): void {
85 if (Date.now() - this.lastTask
> this.maxInactiveTime
) {
86 this.parent?.postMessage({ kill
: 1 })
91 fn
: (data
: Data
) => Response
,
92 value
: { readonly data
: Data
; readonly id
: number }
95 const res
= fn(value
.data
)
96 this.parent?.postMessage({ data
: res
, id
: value
.id
})
97 this.lastTask
= Date.now()
99 this.parent?.postMessage({ error
: e
, id
: value
.id
})
100 this.lastTask
= Date.now()
105 fn
: (data
: Data
) => Promise
<Response
>,
106 value
: { readonly data
: Data
; readonly id
: number }
110 this.parent?.postMessage({ data
: res
, id
: value
.id
})
111 this.lastTask
= Date.now()
114 this.parent?.postMessage({ error
: e
, id
: value
.id
})
115 this.lastTask
= Date.now()