2089b3ef928d95837fafdeaf106dcd33a4bde05c
[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 .execute({ data: req.body }, 'echo')
58 .then(response => {
59 return res.send(response.data).end()
60 })
61 .catch(emptyFunction)
62 })
63
64 application.get('/api/factorial/:number', (req: Request, res: Response) => {
65 const { number } = req.params
66 ExpressWorker.requestHandlerPool
67 .execute({ data: { number: Number.parseInt(number) } }, 'factorial')
68 .then(response => {
69 return res.send(response.data).end()
70 })
71 .catch(emptyFunction)
72 })
73
74 let listenerPort: number | undefined
75 ExpressWorker.server = application.listen(port, () => {
76 listenerPort = (ExpressWorker.server.address() as AddressInfo).port
77 console.info(
78 `⚡️[express server]: Express server is started in cluster worker at http://localhost:${listenerPort.toString()}/`
79 )
80 })
81 return {
82 status: true,
83 port: listenerPort ?? port,
84 }
85 }
86
87 public constructor () {
88 super(ExpressWorker.startExpress, {
89 killHandler: async () => {
90 await ExpressWorker.requestHandlerPool.destroy()
91 ExpressWorker.server.close()
92 },
93 })
94 }
95 }
96
97 export const expressWorker = new ExpressWorker()