diff --git a/server/routers/status-page-router.js b/server/routers/status-page-router.js index 88f788bda..0fe883f08 100644 --- a/server/routers/status-page-router.js +++ b/server/routers/status-page-router.js @@ -91,16 +91,15 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques for (let monitorID of monitorIDList) { let list; - + // Try to use aggregated data from stat tables for better performance const aggregatedData = await getAggregatedHeartbeatData(monitorID, heartbeatRange); - + if (aggregatedData) { // Use pre-aggregated stat data heartbeatList[monitorID] = aggregatedData; } else { // Fall back to raw heartbeat data (auto mode or no stat data) - if (heartbeatRange === "auto") { // Auto mode - use original LIMIT 100 logic list = await R.getAll(` @@ -116,9 +115,8 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques const hours = parseRangeHours(heartbeatRange); const date = new Date(); date.setHours(date.getHours() - hours); - const dateFrom = date.toISOString().slice(0, 19).replace('T', ' '); - - + const dateFrom = date.toISOString().slice(0, 19).replace("T", " "); + list = await R.getAll(` SELECT * FROM heartbeat WHERE monitor_id = ? AND time >= ? diff --git a/server/util/heartbeat-range.js b/server/util/heartbeat-range.js index 745d9d30c..be3c32de4 100644 --- a/server/util/heartbeat-range.js +++ b/server/util/heartbeat-range.js @@ -14,13 +14,13 @@ function parseRangeHours(range) { if (!range || range === "auto") { return null; } - + if (range.endsWith("h")) { return parseInt(range); } else if (range.endsWith("d")) { return parseInt(range) * 24; } - + // Fallback return 90 * 24; } @@ -35,26 +35,26 @@ async function getAggregatedHeartbeatData(monitorId, range) { if (!range || range === "auto") { return null; } - + const now = dayjs(); const hours = parseRangeHours(range); - + if (hours <= 24) { // Use hourly stats for ranges up to 24 hours const startTime = now.subtract(hours, "hours"); const timestampKey = Math.floor(startTime.valueOf() / (60 * 60 * 1000)); // Convert to seconds - + const stats = await R.getAll(` SELECT * FROM stat_hourly WHERE monitor_id = ? AND timestamp >= ? ORDER BY timestamp ASC - `, [monitorId, timestampKey]); - + `, [ monitorId, timestampKey ]); + // If no stat data, fall back to raw heartbeat data if (stats.length === 0) { return null; // This will trigger fallback in router } - + // Convert stat data to simplified format for client-side aggregation const result = stats.map(stat => ({ time: dayjs(stat.timestamp * 1000).format("YYYY-MM-DD HH:mm:ss"), @@ -63,25 +63,25 @@ async function getAggregatedHeartbeatData(monitorId, range) { down: stat.down, ping: stat.ping })); - + return result; } else { // Use daily stats for ranges over 24 hours const days = Math.ceil(hours / 24); const startTime = now.subtract(days, "days"); const timestampKey = Math.floor(startTime.valueOf() / (24 * 60 * 60 * 1000)); // Convert to seconds - + const stats = await R.getAll(` SELECT * FROM stat_daily WHERE monitor_id = ? AND timestamp >= ? ORDER BY timestamp ASC - `, [monitorId, timestampKey]); - + `, [ monitorId, timestampKey ]); + // If no stat data, fall back to raw heartbeat data if (stats.length === 0) { return null; // This will trigger fallback in router } - + // Convert stat data to simplified format for client-side aggregation const result = stats.map(stat => ({ time: dayjs(stat.timestamp * 1000).format("YYYY-MM-DD HH:mm:ss"), @@ -90,7 +90,7 @@ async function getAggregatedHeartbeatData(monitorId, range) { down: stat.down, ping: stat.ping })); - + return result; } } @@ -98,4 +98,4 @@ async function getAggregatedHeartbeatData(monitorId, range) { module.exports = { parseRangeHours, getAggregatedHeartbeatData -}; \ No newline at end of file +}; diff --git a/src/components/HeartbeatBar.vue b/src/components/HeartbeatBar.vue index 40cd34155..92c6c01f3 100644 --- a/src/components/HeartbeatBar.vue +++ b/src/components/HeartbeatBar.vue @@ -99,7 +99,6 @@ export default { }, shortBeatList() { - if (!this.beatList) { return []; } @@ -130,7 +129,6 @@ export default { }, aggregatedBeatList() { - if (!this.beatList || this.beatList.length === 0) { return []; }