Unify URL resolution, add health checker sync, and make modules optional

- Add url-resolver.js with single resolveServiceUrl() used by all 5 consumers
  (probes, health routes, health checker auto-config)
- Health checker now does full sync (add/update/remove) instead of add-only,
  and re-syncs automatically after every services.json mutation
- docker-maintenance and log-digest are now optional imports with try/catch,
  preventing container crashes when these files are absent
- Add null guards in routes/logs.js for graceful 503 responses

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-14 23:01:20 -07:00
parent 70b818c2bd
commit 2815233e86
7 changed files with 145 additions and 106 deletions

View File

@@ -140,6 +140,7 @@ module.exports = function(ctx) {
// Get latest daily digest
router.get('/logs/digest/latest', ctx.asyncHandler(async (req, res) => {
if (!ctx.logDigest) return ctx.errorResponse(res, 503, 'Log digest not available');
const digest = await ctx.logDigest.getLatestDigest();
if (!digest) {
return res.json({ success: true, digest: null, message: 'No digest available yet. First digest is generated at midnight.' });
@@ -149,18 +150,21 @@ module.exports = function(ctx) {
// Get live digest data (today's accumulated stats)
router.get('/logs/digest/live', ctx.asyncHandler(async (req, res) => {
if (!ctx.logDigest) return ctx.errorResponse(res, 503, 'Log digest not available');
const live = ctx.logDigest.getLiveData();
res.json({ success: true, ...live });
}, 'logs-digest-live'));
// List available digest dates
router.get('/logs/digest/history', ctx.asyncHandler(async (req, res) => {
if (!ctx.logDigest) return ctx.errorResponse(res, 503, 'Log digest not available');
const dates = await ctx.logDigest.listDigests();
res.json({ success: true, dates });
}, 'logs-digest-history'));
// Generate digest on demand (for today or a specific date)
router.post('/logs/digest/generate', ctx.asyncHandler(async (req, res) => {
if (!ctx.logDigest) return ctx.errorResponse(res, 503, 'Log digest not available');
const date = req.body.date || new Date().toISOString().slice(0, 10);
const digest = await ctx.logDigest.generateDailyDigest(date);
res.json({ success: true, digest });
@@ -168,6 +172,7 @@ module.exports = function(ctx) {
// Get digest for a specific date (JSON)
router.get('/logs/digest/:date', ctx.asyncHandler(async (req, res) => {
if (!ctx.logDigest) return ctx.errorResponse(res, 503, 'Log digest not available');
const { date } = req.params;
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
return ctx.errorResponse(res, 400, 'Invalid date format. Use YYYY-MM-DD.');
@@ -186,6 +191,7 @@ module.exports = function(ctx) {
// Get Docker disk usage snapshot
router.get('/logs/docker-disk', ctx.asyncHandler(async (req, res) => {
if (!ctx.dockerMaintenance) return ctx.errorResponse(res, 503, 'Docker maintenance not available');
const diskUsage = await ctx.dockerMaintenance.getDiskUsage();
const status = ctx.dockerMaintenance.getStatus();
res.json({ success: true, diskUsage, maintenance: status });
@@ -193,6 +199,7 @@ module.exports = function(ctx) {
// Trigger Docker maintenance manually
router.post('/logs/docker-maintenance', ctx.asyncHandler(async (req, res) => {
if (!ctx.dockerMaintenance) return ctx.errorResponse(res, 503, 'Docker maintenance not available');
const result = await ctx.dockerMaintenance.runMaintenance();
res.json({ success: true, result });
}, 'logs-docker-maintenance'));