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