Stand vor Einführung des Nacht-Agenten
This commit is contained in:
commit
4763548bfb
168 changed files with 12726 additions and 0 deletions
35
apps/api/src/modules/system/index.ts
Normal file
35
apps/api/src/modules/system/index.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import type { FastifyInstance } from 'fastify';
|
||||
import { one } from '../../core/db.js';
|
||||
import { requirePermission } from '../../core/auth.js';
|
||||
import { query } from '../../core/db.js';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import type { KcModule } from '../../core/module.js';
|
||||
|
||||
/** Backup-Zustand aus der Statusdatei des Backup-Laufs (siehe docs/betrieb-backup-restore.md). Ohne Datei: nicht eingerichtet. */
|
||||
async function backupState() {
|
||||
const file = process.env.BACKUP_STATUS_FILE ?? '/var/lib/kundencenter/backup-status.json';
|
||||
let st: any; try { st = JSON.parse(await readFile(file, 'utf8')); } catch { return { configured: false as const }; }
|
||||
const hours = (iso?: string) => (iso ? (Date.now() - new Date(iso).getTime()) / 3600000 : null);
|
||||
const run = st.lastRun; const test = st.lastRestoreTest;
|
||||
return {
|
||||
configured: true as const, lastRunAt: run?.at ?? null, ok: !!run?.ok, ageHours: hours(run?.at), stale: !run || !run.ok || (hours(run.at) ?? 999) > 26, error: run?.error ?? null,
|
||||
file: run?.file ?? null, sizeBytes: run?.sizeBytes ?? null, targets: (run?.targets ?? []).map((t: any) => ({ name: t.name, ok: t.ok })),
|
||||
lastRestoreTestAt: test?.at ?? null, restoreOk: test ? !!test.ok : null, restoreStale: !test || !test.ok || (hours(test.at) ?? 999) > 24 * 10, restoreError: test?.error ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
export const systemModule: KcModule = {
|
||||
name: 'system',
|
||||
register(app: FastifyInstance) {
|
||||
app.get('/health', async () => ({ status: 'ok' })); // Liveness
|
||||
app.get('/ready', async (_req, reply) => { // Readiness: DB erreichbar
|
||||
try { await one('SELECT 1 AS ok'); return { status: 'ready' }; } catch { return reply.code(503).send({ status: 'db_unavailable' }); }
|
||||
});
|
||||
app.get('/admin/system', async (req) => {
|
||||
requirePermission(req, 'jobs.read');
|
||||
const jobs = await query('SELECT status, COUNT(*) AS n FROM jobs GROUP BY status');
|
||||
const oldest = await one('SELECT MIN(run_at) AS t FROM jobs WHERE status IN (\'scheduled\',\'retrying\')');
|
||||
return { jobs: Object.fromEntries(jobs.map((j) => [j.status, Number(j.n)])), oldestPendingJob: oldest?.t ?? null, serverTime: new Date().toISOString(), backup: await backupState() };
|
||||
});
|
||||
},
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue