// Add env vars from files // Note: actual env vars supersede .env file and .env file supersedes .env.defaults file import { config } from 'dotenv-defaults' import { fileURLToPath } from 'node:url' import { dirname, join } from 'node:path' import { randomUUID } from 'node:crypto' import logger from './logger.js' import fastify from 'fastify' import autoLoad from '@fastify/autoload' import { getLatestVersion } from './version.js' import { configMap } from './config_map.js' import * as redis from './redis.js' import { warmCache } from './files.js' import lightship from './lightship.js' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) // Load env vars from .env and .env.defaults files // Note: actual env vars supersede .env file and .env file supersedes .env.defaults file config() lightship.queueBlockingTask(redis.isReady()) lightship.queueBlockingTask(configMap.load()) lightship.queueBlockingTask(getLatestVersion() .then(() => logger.info('[Health] Check latest version on startup.'))) // Create a Fastify server const app = fastify({ requestIdLogLabel: 'requestId', disableRequestLogging: true, logger, connectionTimeout: 30000, // genreqId is used to generate a request id if one is not provided by the proxy genReqId: () => randomUUID() // This is the name of the header used to pass a request id from a proxy to the service // requestIdHeader: 'x-request-id', }) // Register plugins // Note: plugins are loaded in alphabetical order app.register(autoLoad, { dir: join(__dirname, 'plugins') }) // Register routes // Note: routes are loaded in alphabetical order const autoLoadOptions = { dir: join(__dirname, 'routes'), autoHooks: true } if (process.env.APP_ROOT !== '/') autoLoadOptions.options = { prefix: String(process.env.APP_ROOT).replace(/\/$/, '') } app.register(autoLoad, autoLoadOptions) app.addHook('onReady', () => { // don't block the onReady hook getLatestVersion() .then(version => warmCache({ version })) .catch(err => logger.error(err)) }) // This hook is used to signal lightship that the service is ready to receive requests app.addHook('onReady', () => { lightship.signalReady() }) try { // Binds and listens for connections on the specified host and port await app.listen({ host: '::', port: Number(process.env.PORT) }) } catch (err) { logger.error(err) await lightship.shutdown() } lightship.registerShutdownHandler(async () => { logger.info('[Service] Shutting down...') await Promise.all([ redis.client.quit(), redis.pubClient.quit(), redis.subClient.quit() ]) await app.close() })