Skip to content
Snippets Groups Projects
Commit 073b611d authored by richard.petersen's avatar richard.petersen :sailboat:
Browse files

Changed: Replace express with fastify to improve overall performance

parent fd3764d7
No related branches found
No related tags found
No related merge requests found
import createError from 'http-errors'
import path from 'path'
import { logger } from '../logger.js'
export default [function (req, res, next) {
const { body, headers } = res
if (!body) return next(createError(404, 'File does not exist.'))
res.type(headers?.['content-type'] || path.extname(req.path) || 'html')
if (headers) res.set(headers)
res.status(200).send(body)
}, function (err, req, res, next) {
if (!err) next()
if (err.status >= 400 && err.status < 500) logger.warn(err)
else logger.error(err)
res.status(err.status || 500).send(err.message || 'Internal server error occured')
}]
import { getFile } from '../files.js'
import { NotFoundError } from '../errors.js'
import createError from 'http-errors'
export default async function (req, res, next) {
try {
if (req.method !== 'GET') return next()
const version = res.version
const path = req.path === '/' ? '/index.html' : req.path
const { body, headers } = await getFile({ version, path })
res.set(headers)
res.send(body)
} catch (err) {
const errors = err.errors || [err]
const fileNotFound = errors.reduce((memo, error) => memo && error instanceof NotFoundError, true)
if (fileNotFound) next(createError(404, 'File does not exist.'))
else next(err)
}
}
import { getLatestVersion } from '../version.js'
export default async (req, res, next) => {
try {
const latestVersion = await getLatestVersion()
const version = req.get('version') || latestVersion
res.setHeader('version', version)
res.setHeader('latest-version', latestVersion)
res.version = version
} catch (err) {
next(err)
} finally {
next()
}
}
import { Router } from 'express'
import health from '@cloudnative/health-connect'
import * as redis from '../redis.js'
import { getLatestVersion } from '../version.js'
import { once } from '../util.js'
import { config } from '../config.js'
import { logger, timeSinceStartup } from '../logger.js'
const router = Router()
const healthCheck = new health.HealthChecker()
import createError from 'http-errors'
if (redis.isEnabled()) {
const redisReady = new health.ReadinessCheck('Redis ready', redis.isReady)
healthCheck.registerReadinessCheck(redisReady)
const checkRedis = () => {
if (redis.isEnabled()) {
return redis.isReady()
}
}
const checkLatestVersion = new health.StartupCheck('check latest version', once(async function () {
const checkLatestVersion = once(async function () {
// config is required before the first version check
await config.load()
await getLatestVersion()
logger.info(`[Health] Check latest version on startup. Time since startup: ${timeSinceStartup()}`)
}))
})
healthCheck.registerStartupCheck(checkLatestVersion)
async function live () {}
router.use('/live', health.LivenessEndpoint(healthCheck))
router.use('/ready', health.ReadinessEndpoint(healthCheck))
router.use('/healthy', health.HealthEndpoint(healthCheck))
async function ready () {
await Promise.all([
checkLatestVersion(),
checkRedis()
])
}
export default async function healthPlugin (fastify, options) {
fastify.decorate('probe', async (reply, func) => {
try {
await func()
reply.send('')
} catch (err) {
throw createError(503)
}
})
export default router
fastify.get('/live', async (req, reply) => {
await fastify.probe(reply, live)
})
fastify.get('/ready', async (req, reply) => {
await fastify.probe(reply, ready)
})
}
import { Router } from 'express'
import { getOxManifests } from '../manifests.js'
const router = new Router()
router.get('/manifests', async function (req, res, next) {
try {
export default async function manifestsPlugin (fastify, options) {
fastify.get('/manifests', async (req, res) => {
if (res.body) return
res.send(await getOxManifests({ version: res.version }))
} catch (err) {
next(err)
}
})
export default router
})
}
import { Router } from 'express'
import { getMergedMetadata } from '../meta.js'
const router = new Router()
router.get('/meta', async (req, res, next) => {
try {
export default async function metadataPlugin (fastify, options) {
fastify.get('/meta', async (req, res) => {
res.send(await getMergedMetadata({ version: res.version }))
} catch (err) {
next(err)
}
})
export default router
})
}
export default async function redirectsPlugin (fastify, options) {
fastify.get('/ui', async (req, res) => {
res.redirect(process.env.APP_ROOT)
})
fastify.post('/redirect', async (req, res) => {
const location = req.body?.location || '../busy.html'
res.redirect(location)
})
}
import { getFile } from '../files.js'
import { NotFoundError } from '../errors.js'
import createError from 'http-errors'
export default async function serveFilePlugin (fastify, options) {
fastify.get('*', async (req, reply) => {
try {
const version = reply.version
const url = req.url.substr((options.prefix || '/').length - 1)
const path = url === '/' ? '/index.html' : url
const { body, headers } = await getFile({ version, path })
Object.entries(headers).forEach(([key, value]) => {
reply.header(key, value)
})
reply.send(body)
} catch (err) {
const errors = err.errors || [err]
const fileNotFound = errors.reduce((memo, error) => memo && error instanceof NotFoundError, true)
if (fileNotFound) throw createError(404, 'File does not exist.')
throw err
}
})
}
......@@ -6,7 +6,16 @@ const commonQueueOptions = { enableReadyCheck: false, maxRetriesPerRequest: null
const createClient = (type, options = {}) => {
if (!isEnabled()) {
return new Proxy({}, {
return new Proxy({
getBuffer () {},
get () {},
set () {},
del () {},
flushdb () {},
status: '',
duplicate () { return new Redis() },
publish () {}
}, {
get () {
throw new Error('Redis is disabled. Check for redis.isEnabled()')
}
......@@ -15,8 +24,8 @@ const createClient = (type, options = {}) => {
const client = new Redis({
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT || 6379,
db: process.env.REDIS_DB,
port: Number(process.env.REDIS_PORT),
db: Number(process.env.REDIS_DB),
password: process.env.REDIS_PASSWORD,
...options
})
......@@ -43,12 +52,13 @@ const queues = {}
export function getQueue (name) {
if (queues[name]) return queues[name]
// @ts-ignore
return (queues[name] = new Queue(name, {
prefix: process.env.REDIS_PREFIX,
createClient: function (type) {
switch (type) {
case 'client':
return client
return client.duplicate()
case 'subscriber':
return subClient.duplicate()
default:
......
import { Router } from 'express'
const router = new Router()
// backwards compatibility for 7.10.x
// this should hopefully be resolved with an ingress
// or proper config. But is used to be safe on all ends
router.get('/ui', async (req, res, next) => {
res.redirect(process.env.APP_ROOT)
})
router.post('/redirect', (req, res, next) => {
const location = req.body.location || '../busy.html'
res.redirect(location)
})
export default router
......@@ -55,7 +55,7 @@ export function viteToOxManifest (viteManifests) {
.flat()
}
export function getRedisKey ({ version, name }) {
export function getRedisKey ({ version = undefined, name }) {
if (version && name) return `${process.env.REDIS_PREFIX}:${version}:${name}`
return `${process.env.REDIS_PREFIX}:${name}`
}
......@@ -71,4 +71,4 @@ export function once (fn, context) {
return res
}
}
export const t0 = +new Date()
export const t0 = Date.now()
......@@ -40,6 +40,7 @@ export async function getLatestVersion () {
}
}
await config.load()
const version = await fetchLatestVersion()
logger.info(`[Version] Fetched initial version: '${version}'`)
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment