forked from github/docs
- Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
Latest commit
131 lines (105 loc) · 3.63 KB
/
Copy pathserver.js
File metadata and controls
131 lines (105 loc) · 3.63 KB
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
require('dotenv').config()
constthrong=require('throng')
constos=require('os')
constportUsed=require('port-used')
constprefixStreamWrite=require('./lib/prefix-stream-write')
// Intentionally require these for both cluster primary and workers
require('./lib/check-node-version')
require('./lib/handle-exceptions')
require('./lib/feature-flags')
const{PORT,NODE_ENV}=process.env
constport=Number(PORT)||4000
// Start the server!
if(NODE_ENV==='production'){
clusteredMain()
}else{
nonClusteredMain()
}
functionclusteredMain(){
// Spin up a cluster!
throng({
master: setupPrimary,
worker: setupWorker,
count: calculateWorkerCount()
})
}
asyncfunctionnonClusteredMain(){
awaitcheckPortAvailability()
awaitstartServer()
}
asyncfunctioncheckPortAvailability(){
// Check that the development server is not already running
constportInUse=awaitportUsed.check(port)
if(portInUse){
console.log(`\n\n\nPort ${port} is not available. You may already have a server running.`)
console.log('Try running `killall node` to shut down all your running node processes.\n\n\n')
console.log('\x07')// system 'beep' sound
process.exit(1)
}
}
asyncfunctionstartServer(){
constapp=require('./lib/app')
constwarmServer=require('./lib/warm-server')
// If in a deployed environment...
if(NODE_ENV==='production'){
// If in a true production environment, wait for the cache to be fully warmed.
if(process.env.HEROKU_PRODUCTION_APP||process.env.GITHUB_ACTIONS){
awaitwarmServer()
}
}
// Workaround for https://github.com/expressjs/express/issues/1101
constserver=require('http').createServer(app)
server
.listen(port,()=>console.log(`app running on http://localhost:${port}`))
.on('error',()=>server.close())
}
// This function will only be run in the primary process
asyncfunctionsetupPrimary(){
process.on('beforeExit',()=>{
console.log('Shutting down primary...')
console.log('Exiting!')
})
console.log('Starting up primary...')
awaitcheckPortAvailability()
}
// IMPORTANT: This function will be run in a separate worker process!
asyncfunctionsetupWorker(id,disconnect){
letexited=false
// Wrap stdout and stderr to include the worker ID as a static prefix
// console.log('hi') => '[worker.1]: hi'
constprefix=`[worker.${id}]: `
prefixStreamWrite(process.stdout,prefix)
prefixStreamWrite(process.stderr,prefix)
process.on('beforeExit',()=>{
console.log('Exiting!')
})
process.on('SIGTERM',shutdown)
process.on('SIGINT',shutdown)
console.log('Starting up worker...')
// Load the server in each worker process and share the port via sharding
awaitstartServer()
functionshutdown(){
if(exited)return
exited=true
console.log('Shutting down worker...')
disconnect()
}
}
functioncalculateWorkerCount(){
// Heroku's recommended WEB_CONCURRENCY count based on the WEB_MEMORY config,
// or explicitly configured by us
const{WEB_CONCURRENCY}=process.env
constrecommendedCount=parseInt(WEB_CONCURRENCY,10)
constcpuCount=os.cpus().length
// Ensure the recommended count is AT LEAST 1 for safety
letworkerCount=Math.max(recommendedCount||1,1)
// If WEB_CONCURRENCY value was configured to a valid number...
if(recommendedCount>0){
// Use the smaller value between the recommendation vs. the CPU count
workerCount=Math.min(workerCount,cpuCount)
}elseif(NODE_ENV==='production'){
// Else if in a deployed environment, default to the CPU count
workerCount=cpuCount
}
returnworkerCount
}