Commit | Line | Data |
---|---|---|
a449b585 JB |
1 | import type { Server } from 'node:http' |
2 | import type { AddressInfo } from 'node:net' | |
d0ed34c9 JB |
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 => { | |
8ea47589 | 18 | /* Intentional */ |
d0ed34c9 JB |
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 => { | |
7d9756e3 | 34 | const { port, workerFile, minWorkers, maxWorkers, ...poolOptions } = |
67f3f2d6 | 35 | workerData! |
d0ed34c9 JB |
36 | |
37 | ExpressWorker.requestHandlerPool = new DynamicThreadPool< | |
38 | ThreadWorkerData<DataPayload>, | |
39 | ThreadWorkerResponse<DataPayload> | |
40 | >( | |
41 | minWorkers ?? 1, | |
42 | maxWorkers ?? availableParallelism(), | |
43 | workerFile, | |
7d9756e3 | 44 | poolOptions |
d0ed34c9 JB |
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') | |
041dc05b | 55 | .then(response => { |
d0ed34c9 JB |
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') | |
041dc05b | 65 | .then(response => { |
d0ed34c9 JB |
66 | return res.send(response.data).end() |
67 | }) | |
68 | .catch(emptyFunction) | |
69 | }) | |
70 | ||
71 | ExpressWorker.server = application.listen(port, () => { | |
72 | console.info( | |
1fa0cdf5 | 73 | `⚡️[express server]: Express server is started in cluster worker at http://localhost:${port}/` |
d0ed34c9 JB |
74 | ) |
75 | }) | |
76 | return { | |
77 | status: true, | |
c63a35a0 | 78 | port: (ExpressWorker.server.address() as AddressInfo).port |
d0ed34c9 JB |
79 | } |
80 | } | |
81 | ||
82 | public constructor () { | |
83 | super(ExpressWorker.startExpress, { | |
84 | killHandler: async () => { | |
85 | await ExpressWorker.requestHandlerPool.destroy() | |
86 | ExpressWorker.server.close() | |
87 | } | |
88 | }) | |
89 | } | |
90 | } | |
91 | ||
92 | export const expressWorker = new ExpressWorker() |