postgres uptime

This commit is contained in:
Heidi
2026-05-14 21:16:06 +01:00
parent 11e076394b
commit e58adcc716
7 changed files with 466 additions and 59 deletions
+78 -57
View File
@@ -10,6 +10,7 @@ const dateFormat = new Intl.DateTimeFormat('en-GB', {
const apiEndpoints = {
health: '/health',
uptime: '/api/uptime',
teams: '/api/tss/leaderboard/teams?limit=100',
teamsHealth: '/api/tss/leaderboard/teams?limit=1',
resolve: (name) => `/api/tss/teams/resolve?name=${encodeURIComponent(name)}`,
@@ -322,7 +323,7 @@ function App() {
const controller = new AbortController()
async function checkUptime() {
async function loadUptime() {
setUptime((current) => ({
status: current.status === 'ready' ? 'refreshing' : 'loading',
checks: current.checks,
@@ -330,65 +331,85 @@ function App() {
updatedAt: current.updatedAt,
}))
const startedAt = performance.now()
const healthResult = await fetchJson(apiEndpoints.health, controller.signal)
.then(() => ({ ok: true, label: 'Operational' }))
.catch((error) => ({ ok: false, label: error.message }))
const apiResult = await fetchJson(apiEndpoints.teamsHealth, controller.signal)
fetchJson(apiEndpoints.uptime, controller.signal)
.then((data) => {
const teamCount = data.teams?.length || data.squadrons?.length || 0
return { ok: true, label: `${teamCount} sample team${teamCount === 1 ? '' : 's'} returned` }
const latest = data.latest
const checks = latest
? [
{
name: 'Website',
detail: 'App shell and static assets',
ok: latest.website_ok,
label: latest.details?.website?.label || (latest.website_ok ? 'Online' : 'Issue'),
latency: latest.latency_ms,
},
{
name: 'Health endpoint',
detail: apiEndpoints.health,
ok: latest.health_ok,
label: latest.details?.health?.label || (latest.health_ok ? 'Operational' : 'Issue'),
latency: latest.latency_ms,
},
{
name: 'TSS data proxy',
detail: apiEndpoints.teamsHealth,
ok: latest.tss_ok,
label: latest.details?.tss?.label || (latest.tss_ok ? 'Operational' : 'Issue'),
latency: latest.details?.tss?.latency_ms || latest.latency_ms,
},
]
: []
setUptime({
status: 'ready',
checks,
history: (data.history || []).map((sample) => ({
timestamp: new Date(sample.checked_at).getTime(),
onlineChecks: [sample.website_ok, sample.health_ok, sample.tss_ok].filter(Boolean).length,
totalChecks: 3,
ok: sample.ok,
})),
updatedAt: latest ? new Date(latest.checked_at).getTime() : null,
configured: data.configured,
})
})
.catch((error) => ({ ok: false, label: error.message }))
.catch((error) => {
if (controller.signal.aborted) return
if (controller.signal.aborted) return
setUptime((current) => {
const checks = [
{
name: 'Website',
detail: 'App shell and static assets',
ok: true,
label: 'Online',
latency: Math.round(performance.now() - startedAt),
},
{
name: 'Health endpoint',
detail: apiEndpoints.health,
ok: healthResult.ok,
label: healthResult.label,
latency: Math.round(performance.now() - startedAt),
},
{
name: 'TSS data proxy',
detail: apiEndpoints.teamsHealth,
ok: apiResult.ok,
label: apiResult.label,
latency: Math.round(performance.now() - startedAt),
},
]
const onlineChecks = checks.filter((check) => check.ok).length
return {
status: 'ready',
updatedAt: Date.now(),
checks,
history: [
...current.history,
{
timestamp: Date.now(),
onlineChecks,
totalChecks: checks.length,
ok: onlineChecks === checks.length,
},
].slice(-48),
}
})
setUptime({
status: 'error',
updatedAt: null,
configured: false,
history: [],
checks: [
{
name: 'Website',
detail: 'App shell and static assets',
ok: true,
label: 'Online',
latency: 0,
},
{
name: 'Health endpoint',
detail: apiEndpoints.health,
ok: false,
label: error.message,
latency: 0,
},
{
name: 'TSS data proxy',
detail: apiEndpoints.teamsHealth,
ok: false,
label: 'Uptime history unavailable',
latency: 0,
},
],
})
})
}
checkUptime()
const timer = window.setInterval(checkUptime, 30000)
loadUptime()
const timer = window.setInterval(loadUptime, 60000)
return () => {
window.clearInterval(timer)
@@ -1093,7 +1114,7 @@ function UptimePage({ uptime }) {
{allOperational ? 'All systems operational' : 'Status check'}
</h1>
<p className="mt-2 text-sm text-text-soft">
Last checked {updatedAt}. Refreshes every 30 seconds while this page is open.
Last server snapshot {updatedAt}. The page refreshes once a minute.
</p>
</div>
<span
@@ -1112,7 +1133,7 @@ function UptimePage({ uptime }) {
<div>
<h2 className="text-lg font-semibold">Availability timeline</h2>
<p className="mt-1 text-sm text-text-soft">
Last {formatNumber(history.length)} checks from this browser session
Last {formatNumber(history.length)} persisted server snapshots
</p>
</div>
<p className="text-sm font-semibold text-fury-cyan">