feat: add express-hybrid-pool example
[poolifier.git] / examples / typescript / http-server-pool / express-hybrid / src / express-worker.ts
1 import type { Server } from 'http'
2 import type { AddressInfo } from 'net'
3 import {
4 ClusterWorker,
5 DynamicThreadPool,
6 availableParallelism
7 } from 'poolifier'
8 import express, { type Express, type Request, type Response } from 'express'
9 import {
10 type ClusterWorkerData,
11 type ClusterWorkerResponse,
12 type DataPayload,
13 type ThreadWorkerData,
14 type ThreadWorkerResponse
15 } from './types.js'
16
17 const emptyFunction = (): void => {
18 /** Intentional */
19 }
20
21 class ExpressWorker extends ClusterWorker<
22 ClusterWorkerData,
23 ClusterWorkerResponse
24 > {
25 private static server: Server
26 private static requestHandlerPool: DynamicThreadPool<
27 ThreadWorkerData<DataPayload>,
28 ThreadWorkerResponse<DataPayload>
29 >
30
31 private static readonly startExpress = (
32 workerData?: ClusterWorkerData
33 ): ClusterWorkerResponse => {
34 const { port, workerFile, minWorkers, maxWorkers } =
35 workerData as ClusterWorkerData
36
37 ExpressWorker.requestHandlerPool = new DynamicThreadPool<
38 ThreadWorkerData<DataPayload>,
39 ThreadWorkerResponse<DataPayload>
40 >(
41 minWorkers ?? 1,
42 maxWorkers ?? availableParallelism(),
43 workerFile,
44 workerData
45 )
46
47 const application: Express = express()
48
49 // Parse only JSON requests body
50 application.use(express.json())
51
52 application.all('/api/echo', (req: Request, res: Response) => {
53 ExpressWorker.requestHandlerPool
54 .execute({ data: req.body }, 'echo')
55 .then((response) => {
56 return res.send(response.data).end()
57 })
58 .catch(emptyFunction)
59 })
60
61 application.get('/api/factorial/:number', (req: Request, res: Response) => {
62 const { number } = req.params
63 ExpressWorker.requestHandlerPool
64 .execute({ data: { number: parseInt(number) } }, 'factorial')
65 .then((response) => {
66 return res.send(response.data).end()
67 })
68 .catch(emptyFunction)
69 })
70
71 ExpressWorker.server = application.listen(port, () => {
72 console.info(
73 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
74 `⚡️[express server]: Express server is started in cluster worker at http://localhost:${workerData?.port}/`
75 )
76 })
77 return {
78 status: true,
79 port:
80 (ExpressWorker.server.address() as AddressInfo)?.port ??
81 workerData?.port
82 }
83 }
84
85 public constructor () {
86 super(ExpressWorker.startExpress, {
87 killHandler: async () => {
88 await ExpressWorker.requestHandlerPool.destroy()
89 ExpressWorker.server.close()
90 }
91 })
92 }
93 }
94
95 export const expressWorker = new ExpressWorker()