mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
a869269591
Changing PORT left the Dockerfile and compose healthchecks, the chart's containerPort, Service target and probes on 3000, so the container went unhealthy and Kubernetes restarted it in a loop. All of them follow PORT now. The chart gains a startup probe (ten minutes for a first boot, a long migration or a restore at boot, which liveness used to kill after about 105 s), a readiness probe on the new /api/health/ready that asks the database, extraEnv and extraEnvFrom for the settings the chart does not list, slots for the four secrets it had none for, and the DEFAULT_LANGUAGE and MCP_MAX_SESSION_PER_USER values it documented but never set. The Dockerfile no longer hides a failed npm ci behind a ';', pins gosu, and the language lists name all 27 locales.
57 lines
2.2 KiB
TypeScript
57 lines
2.2 KiB
TypeScript
import { Controller, Get, Res } from '@nestjs/common';
|
|
import { EntityManager } from '@mikro-orm/core';
|
|
import type { Response } from 'express';
|
|
import { MaintenanceRepository } from '../../db/repositories/MaintenanceRepository';
|
|
import { KitineraryExtractorService } from '../booking-import/kitinerary-extractor.service';
|
|
import { AddonsService } from '../addons/addons.service';
|
|
import { ADDON_IDS } from '../../addons';
|
|
import { Public } from '../auth/public.decorator';
|
|
|
|
/** Exposes the container probe and the server feature flags consumed by the
|
|
* frontend to show/hide optional UI. */
|
|
@Public('server capability flags the login screen reads to decide what to offer')
|
|
@Controller('api/health')
|
|
export class FeaturesController {
|
|
constructor(
|
|
private readonly extractor: KitineraryExtractorService,
|
|
private readonly addons: AddonsService,
|
|
private readonly em: EntityManager,
|
|
) {}
|
|
|
|
/** The container/uptime probe. The forced-HTTPS redirect and HSTS exempt this
|
|
* path inside globalMiddleware, so probes work regardless of proxy setup;
|
|
* @Res() keeps the exact legacy header casing and body bytes. */
|
|
@Get()
|
|
health(@Res() res: Response): void {
|
|
res.setHeader('Cache-Control', 'no-store, must-revalidate');
|
|
res.json({ status: 'ok' });
|
|
}
|
|
|
|
/**
|
|
* The readiness probe: 503 while the database does not answer (a restore
|
|
* swapping it, a boot still migrating), so an orchestrator stops sending
|
|
* traffic without killing the process. Liveness stays on the plain probe
|
|
* above, which a long restore must not fail.
|
|
*/
|
|
@Get('ready')
|
|
async ready(@Res() res: Response): Promise<void> {
|
|
res.setHeader('Cache-Control', 'no-store, must-revalidate');
|
|
try {
|
|
await new MaintenanceRepository(this.em).ping();
|
|
res.json({ status: 'ready' });
|
|
} catch {
|
|
res.status(503).json({ status: 'unavailable' });
|
|
}
|
|
}
|
|
|
|
@Get('features')
|
|
async features() {
|
|
return {
|
|
bookingImport: this.extractor.isAvailable(),
|
|
// Addon-level flag (per-user config availability is reported per-file in
|
|
// the preview response). Drives whether the client shows AI affordances.
|
|
aiParsing: await this.addons.isAddonEnabled(ADDON_IDS.LLM_PARSING),
|
|
};
|
|
}
|
|
}
|