Skip to content
Snippets Groups Projects
server.js 2.29 KiB
process.title = 'Jetsam API Server'

const redbird = require('redbird')
const Koa = require('koa')
const app = require('app')
const http = require('http')
const { config, env, fs, boot } = require('bootstrap')
const debug = require('debug')('server:boot')
const pkg = require('./package.json')

const Sentry = require('@sentry/node')
const Tracing = require('@sentry/tracing')

let server = null
let worker = null

function bindSentry(app) {
	const sentryUtil = require('vendor/sentry')
	sentryUtil.configure()

	debug('Binding sentry to app level errors')

	app.on('error', (err, ctx) => {
		console.error(err)
		Sentry.withScope(function (scope) {
			scope.addEventProcessor(function (event) {
				return Sentry.Handlers.parseRequest(event, ctx.request)
			})
			Sentry.captureException(err)
		})
	})
}

async function launch(
	port = 0,
	host = config('app.host.web', `http://localhost:${port}`),
) {
	const koa = new Koa()
	const appserver = await app(koa)

	if (config('sentry.enabled')) {
		bindSentry(koa)
	}

	const httpServer = http.createServer(appserver.callback())
	httpServer.listen(port)
	debug(`Listening on ${host}`)

	server = httpServer

	maybeSpawnWorker()

	return httpServer
}

async function runProxy() {
	const port = config('app.port')
	const proxy = redbird({ port, bunyan: false })
	const hosts = config('services.proxy.hosts')

	await launch()

	const address = server.address()
	if (!address) {
		throw new Error('Failed to start')
	}

	debug(`Binding hosts [${hosts.join(', ')}] to server port ${address.port}`)
	for (const host of hosts) {
		proxy.register(host, `http://127.0.0.1:${address.port}`)
	}
}

function maybeSpawnWorker() {
	if (config('queue.driver') === 'async') {
		debug('Spawning async worker')
		const bindQueue = require('core/utils/queue')
		const { queue } = require('services')

		bindQueue()
		worker = queue.listen()
	}
}

async function main() {
	await boot()

	if (config('services.proxy.enabled')) {
		return await runProxy()
	} else {
		return await launch(config('app.port'))
	}
}

main().catch(e => {
	console.error(e)
	process.exit(1)
})

const cleanupsigs = ['SIGINT', 'SIGTERM', 'SIGUSR2']

cleanupsigs.forEach(signal => {
	process.on(signal, () => {
		if (worker) {
			worker()
		}
		if (server) {
			server.close()
		}
		Sentry.close(2000).then(() => {
			process.exit(0)
		})
	})
})