tinylink/core/http.js
mahdahar 10f8dbbb83 refactor: consolidate core runtime and docs
Move middleware sources into core/, refresh config paths, and update design/user docs to reflect the raw payload pipeline.
2026-04-07 11:30:11 +07:00

95 lines
3.1 KiB
JavaScript

const express = require('express');
const queue = require('./queue/queue');
const instrumentConfig = require('./config/instrumentConfig');
function createHealthRouter(connectors = []) {
const router = express.Router();
router.get('/', async (req, res) => {
const connectorStatuses = connectors.map((connector) => connector.health());
const pending = await queue.pendingCount();
const retrying = await queue.retryingCount();
const deadLetters = await queue.deadLetterCount();
res.json({
status: 'ok',
connectors: connectorStatuses,
metrics: {
pending,
retrying,
deadLetters
}
});
});
router.get('/ready', async (req, res) => {
try {
await queue.ping();
res.json({ status: 'ready' });
} catch (err) {
res.status(503).json({ status: 'unready', reason: err.message });
}
});
return router;
}
const instrumentRouter = express.Router();
instrumentRouter.get('/', async (req, res) => {
res.json(instrumentConfig.list());
});
instrumentRouter.get('/:id', async (req, res) => {
const entry = instrumentConfig.get(req.params.id);
if (!entry) {
return res.status(404).json({ error: 'not found' });
}
res.json(entry);
});
const metricsRouter = express.Router();
function formatMetric(name, value, type = 'gauge', help = '') {
const lines = [];
if (help) {
lines.push(`# HELP ${name} ${help}`);
}
lines.push(`# TYPE ${name} ${type}`);
lines.push(`${name} ${value}`);
return lines.join('\n');
}
metricsRouter.get('/', async (req, res) => {
try {
const pending = await queue.pendingCount();
const retrying = await queue.retryingCount();
const deadLetters = await queue.deadLetterCount();
const lastSuccess = await queue.getLastSuccessTimestamp();
const avgLatency = await queue.getAverageLatency();
const attempts = await queue.getDeliveryAttempts();
const timestamp = lastSuccess ? new Date(lastSuccess).getTime() / 1000 : 0;
const metrics = [
formatMetric('workstation_pending_total', pending, 'gauge', 'Number of pending payloads'),
formatMetric('workstation_retrying_total', retrying, 'gauge', 'Number of payloads currently retrying'),
formatMetric('workstation_dead_letters_total', deadLetters, 'gauge', 'Total dead-lettered payloads'),
formatMetric('workstation_delivery_attempts_total', attempts, 'counter', 'Total delivery attempts logged'),
formatMetric('workstation_last_success_timestamp', timestamp, 'gauge', 'Epoch seconds of last successful delivery'),
formatMetric('workstation_avg_latency_ms', Math.round(avgLatency), 'gauge', 'Average delivery latency in milliseconds')
];
res.set('content-type', 'text/plain; version=0.0.4; charset=utf-8');
res.send(metrics.join('\n'));
} catch (error) {
res.status(500).send('metrics unavailable');
}
});
function createHttpServer(connectors) {
const app = express();
app.use('/health', createHealthRouter(connectors));
app.use('/instruments', instrumentRouter);
app.use('/metrics', metricsRouter);
return app;
}
module.exports = { createHttpServer };