-
Notifications
You must be signed in to change notification settings - Fork 27.4k
/
Copy pathrender-server.ts
141 lines (122 loc) · 3.64 KB
/
render-server.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import type { RequestHandler } from '../next'
import v8 from 'v8'
import http from 'http'
import { isIPv6 } from 'net'
// This is required before other imports to ensure the require hook is setup.
import '../require-hook'
import next from '../next'
import { warn } from '../../build/output/log'
import {
deleteCache as _deleteCache,
deleteAppClientCache as _deleteAppClientCache,
} from '../../build/webpack/plugins/nextjs-require-cache-hot-reloader'
import { clearModuleContext as _clearModuleContext } from '../web/sandbox/context'
import { getFreePort } from '../lib/worker-utils'
export const WORKER_SELF_EXIT_CODE = 77
const MAXIMUM_HEAP_SIZE_ALLOWED =
(v8.getHeapStatistics().heap_size_limit / 1024 / 1024) * 0.9
let result:
| undefined
| {
port: number
hostname: string
}
export function clearModuleContext(target: string, content: string) {
_clearModuleContext(target, content)
}
export function deleteAppClientCache() {
_deleteAppClientCache()
}
export function deleteCache(filePath: string) {
_deleteCache(filePath)
}
export async function initialize(opts: {
dir: string
port: number
dev: boolean
minimalMode?: boolean
hostname?: string
workerType: 'router' | 'render'
isNodeDebugging: boolean
keepAliveTimeout?: number
}): Promise<NonNullable<typeof result>> {
// if we already setup the server return as we only need to do
// this on first worker boot
if (result) {
return result
}
let requestHandler: RequestHandler
const server = http.createServer((req, res) => {
return requestHandler(req, res)
.catch((err) => {
res.statusCode = 500
res.end('Internal Server Error')
console.error(err)
})
.finally(() => {
if (
process.memoryUsage().heapUsed / 1024 / 1024 >
MAXIMUM_HEAP_SIZE_ALLOWED
) {
warn(
'The server is running out of memory, restarting to free up memory.'
)
server.close()
process.exit(WORKER_SELF_EXIT_CODE)
}
})
})
if (opts.keepAliveTimeout) {
server.keepAliveTimeout = opts.keepAliveTimeout
}
return new Promise(async (resolve, reject) => {
server.on('error', (err: NodeJS.ErrnoException) => {
console.error(`Invariant: failed to start render worker`, err)
process.exit(1)
})
let upgradeHandler: any
if (!opts.dev) {
server.on('upgrade', (req, socket, upgrade) => {
upgradeHandler(req, socket, upgrade)
})
}
server.on('listening', async () => {
try {
const addr = server.address()
const port = addr && typeof addr === 'object' ? addr.port : 0
if (!port) {
console.error(`Invariant failed to detect render worker port`, addr)
process.exit(1)
}
let hostname =
!opts.hostname || opts.hostname === '0.0.0.0'
? 'localhost'
: opts.hostname
if (isIPv6(hostname)) {
hostname = hostname === '::' ? '[::1]' : `[${hostname}]`
}
result = {
port,
hostname,
}
const app = next({
...opts,
_routerWorker: opts.workerType === 'router',
_renderWorker: opts.workerType === 'render',
hostname,
customServer: false,
httpServer: server,
port: opts.port,
isNodeDebugging: opts.isNodeDebugging,
})
requestHandler = app.getRequestHandler()
upgradeHandler = app.getUpgradeHandler()
await app.prepare()
resolve(result)
} catch (err) {
return reject(err)
}
})
server.listen(await getFreePort(), opts.hostname)
})
}