Add ability to run server cluster

This commit is contained in:
Jerko Steiner 2019-10-12 08:44:21 -05:00
parent 0633734156
commit 17adb818be
3 changed files with 73 additions and 20 deletions

View File

@ -8,6 +8,8 @@ export interface Bootstrap {
readonly database: TypeORMDatabase
getConfig(): Config
listen(port?: number | string, hostname?: string): Promise<void>
startCluster(
workers: number, port?: number | string, hostname?: string): Promise<void>
getAddress(): AddressInfo | string
close(): Promise<void>
}

View File

@ -1,5 +1,7 @@
import { TypeORMDatabase, TypeORMLogger } from '@rondo.dev/db-typeorm'
import assert from 'assert'
import { createNamespace, Namespace } from 'cls-hooked'
import cluster from 'cluster'
import { Server } from 'http'
import { AddressInfo } from 'net'
import { loggerFactory } from '../logger'
@ -8,7 +10,7 @@ import { Bootstrap } from './Bootstrap'
import { Config } from './Config'
import { ServerConfigurator } from './configureServer'
import { createServer } from './createServer'
import { TypeORMDatabase, TypeORMLogger } from '@rondo.dev/db-typeorm'
export interface ServerBootstrapParams {
readonly config: Config
@ -79,7 +81,7 @@ export class ServerBootstrap implements Bootstrap {
async listen(
port: number | string | undefined = process.env.PORT || 3000,
hostname: string | undefined= process.env.BIND_HOST,
hostname: string | undefined = process.env.BIND_HOST,
) {
const apiLogger = loggerFactory.getLogger('api')
try {
@ -91,6 +93,36 @@ export class ServerBootstrap implements Bootstrap {
}
}
async startCluster(
workers: number,
port?: number | string,
hostname?: string,
) {
const apiLogger = loggerFactory.getLogger('api')
if (cluster.isMaster) {
apiLogger.info('Started master process %d, starting %d workers...',
process.pid, workers)
// Fork workers.
for (let i = 0; i < workers; i++) {
cluster.fork({
WORKER_ID: i + 1,
})
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`)
})
} else {
await this.listen(port, hostname)
apiLogger.info(
'Started worker %d (worker id %s)', process.pid, process.env.WORKER_ID)
}
}
protected async start(
port: number | string | undefined = process.env.PORT,
hostname?: string,

View File

@ -1,8 +1,28 @@
import { Bootstrap } from "../application";
import { argparse, arg } from "@rondo.dev/argparse";
import { arg, argparse } from '@rondo.dev/argparse'
import { cpus } from 'os'
import { Bootstrap } from '../application'
const numberOfCPUs = cpus().length
const startArgs = {
host: arg('string', {
description: '',
}),
socket: arg('number', {
alias: 's',
description: 'Socket to listen on',
}),
port: arg('number', {
default: 3000,
alias: 'p',
description: 'Port to listen on',
}),
help: arg('boolean', {alias: 'h'}),
}
export function run(bootstrap: Bootstrap, argv: string[]) {
const choices: Array<keyof typeof commands> = ['start', 'migrate']
const choices: Array<keyof typeof commands> = Object
.keys(commands) as Array<keyof typeof commands>
const {parse} = argparse({
command: arg('string', {
default: 'start',
@ -24,24 +44,23 @@ export function run(bootstrap: Bootstrap, argv: string[]) {
const commands = {
async start(bootstrap: Bootstrap, argv: string[]) {
const {parse} = argparse({
host: arg('string', {
description: '',
}),
socket: arg('number', {
alias: 's',
description: 'Socket to listen on',
}),
port: arg('number', {
default: 3000,
alias: 'p',
description: 'Port to listen on',
}),
help: arg('boolean', {alias: 'h'}),
})
const {parse} = argparse(startArgs, 'Start the server')
const args = parse(argv)
await bootstrap.listen(args.port || args.socket, args.host)
},
async cluster(bootstrap: Bootstrap, argv: string[]) {
const {parse} = argparse({
...startArgs,
workers: arg('number', {
alias: 'w',
description: 'Number of workers to start',
default: numberOfCPUs,
}),
}, 'Start in cluster')
const args = parse(argv)
await bootstrap
.startCluster(args.workers, args.port || args.socket, args.host)
},
async migrate(bootstrap: Bootstrap, argv: string[]) {
const {parse} = argparse({
undo: arg('boolean', {