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