Skip to content

Instantly share code, notes, and snippets.

@kofigumbs
Last active February 26, 2024 01:04
Show Gist options
  • Save kofigumbs/2b3a4eb856b4bed406a04f6ecea22e99 to your computer and use it in GitHub Desktop.
Save kofigumbs/2b3a4eb856b4bed406a04f6ecea22e99 to your computer and use it in GitHub Desktop.
Zero-downtime Node deploys using parent process proxy, early exploration for https://kofi.sexy/blog/zero-downtime-render-disk
import { spawn } from 'child_process'
import { createServer, request } from 'http'
import pidtree from 'pidtree'
const deployCommand = ['npm', ['start']]
const deployWait = 30 * 1000
const deploySecretPath = '/~deploy-01HPZ2ACGJSJJ0NGX9MT1RYRDB'
let server = startServer(8001)
const proxy = createServer((clientRequest, clientResponse) => {
if (clientRequest.url === deploySecretPath) {
restartServer()
clientResponse.writeHead(202).end()
return
}
const forward = {
method: clientRequest.method,
headers: clientRequest.headers,
path: clientRequest.url,
port: server.PORT,
}
const serverRequest = request(forward, (serverResponse) => {
clientResponse.writeHead(serverResponse.statusCode, serverResponse.headers)
serverResponse.pipe(clientResponse, { end: true })
})
serverRequest.on('error', (error) => {
handleError(error)
clientResponse.writeHead(502).end()
})
clientRequest.pipe(serverRequest, { end: true })
})
function startServer(PORT) {
return {
process: spawn(...deployCommand, { stdio: 'inherit', env: { ...process.env, PORT } }).on('error', console.error),
PORT,
}
}
function restartServer() {
if (server.stopping)
return
server.stopping = true
const oldServer = server
const newServer = startServer(server.PORT + 1)
setTimeout(
() => {
server = newServer
pidtree(oldServer.process.pid, { root: true }).then((pids) => pids.map((pid) => process.kill(pid)), console.error)
},
deployWait,
)
}
proxy.listen(10000)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment