overleaf/services/history-v1/backup-deletion-app.mjs
Jakob Ackermann 9cc6f2a9d5 Merge pull request #21829 from overleaf/jpa-backup-deletion
[history-v1] backup-deletion-app: initial revision

GitOrigin-RevId: 9e05c0e16595cb8d180861ef503c7b4522110d39
2024-11-18 09:05:44 +00:00

81 lines
2.1 KiB
JavaScript

// @ts-check
// Metrics must be initialized before importing anything else
import '@overleaf/metrics/initialize.js'
import http from 'node:http'
import { fileURLToPath } from 'node:url'
import { promisify } from 'node:util'
import express from 'express'
import logger from '@overleaf/logger'
import Metrics from '@overleaf/metrics'
import { hasValidBasicAuthCredentials } from './api/app/security.js'
import {
deleteProjectBackupCb,
healthCheck,
healthCheckCb,
NotReadyToDelete,
} from './storage/lib/backupDeletion.mjs'
import { mongodb } from './storage/index.js'
const app = express()
logger.initialize('history-v1-backup-deletion')
Metrics.open_sockets.monitor()
Metrics.injectMetricsRoute(app)
app.use(Metrics.http.monitor(logger))
Metrics.leaked_sockets.monitor(logger)
Metrics.event_loop.monitor(logger)
Metrics.memory.monitor(logger)
function basicAuth(req, res, next) {
if (hasValidBasicAuthCredentials(req)) return next()
res.setHeader('WWW-Authenticate', 'Basic realm="Application"')
res.sendStatus(401)
}
app.delete('/project/:projectId/backup', basicAuth, (req, res, next) => {
deleteProjectBackupCb(req.params.projectId, err => {
if (err) {
return next(err)
}
res.sendStatus(204)
})
})
app.get('/status', (req, res) => {
res.send('history-v1-backup-deletion is up')
})
app.get('/health_check', (req, res, next) => {
healthCheckCb(err => {
if (err) return next(err)
res.sendStatus(200)
})
})
app.use((err, req, res, next) => {
req.logger.addFields({ err })
if (err instanceof NotReadyToDelete) {
req.logger.setLevel('warn')
return res.status(422).send(err.message)
}
req.logger.setLevel('error')
next(err)
})
/**
* @param {number} port
* @return {Promise<http.Server>}
*/
export async function startApp(port) {
await mongodb.client.connect()
await healthCheck()
const server = http.createServer(app)
await promisify(server.listen.bind(server, port))()
return server
}
// Run this if we're called directly
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const PORT = parseInt(process.env.PORT || '3101', 10)
await startApp(PORT)
}