mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-06-19 10:46:48 +02:00
Merge 2dc3e1ab1f
into 443d5cf554
This commit is contained in:
commit
b6e70293fa
2 changed files with 101 additions and 5 deletions
|
@ -7,7 +7,6 @@ const path = require("path");
|
|||
const { EmbeddedMariaDB } = require("./embedded-mariadb");
|
||||
const mysql = require("mysql2/promise");
|
||||
const { Settings } = require("./settings");
|
||||
const { UptimeCalculator } = require("./uptime-calculator");
|
||||
const dayjs = require("dayjs");
|
||||
const { SimpleMigrationServer } = require("./utils/simple-migration-server");
|
||||
const KumaColumnCompiler = require("./utils/knex/lib/dialects/mysql2/schema/mysql2-columncompiler");
|
||||
|
@ -217,6 +216,7 @@ class Database {
|
|||
dbConfig = {
|
||||
type: "sqlite",
|
||||
};
|
||||
Database.dbConfig = dbConfig; // Fix: Also set Database.dbConfig in catch block
|
||||
}
|
||||
|
||||
let config = {};
|
||||
|
@ -823,7 +823,8 @@ class Database {
|
|||
]);
|
||||
|
||||
for (let date of dates) {
|
||||
// New Uptime Calculator
|
||||
// New Uptime Calculator - import locally to avoid circular dependency
|
||||
const { UptimeCalculator } = require("./uptime-calculator");
|
||||
let calculator = new UptimeCalculator();
|
||||
calculator.monitorID = monitor.monitor_id;
|
||||
calculator.setMigrationMode(true);
|
||||
|
|
|
@ -306,7 +306,14 @@ class UptimeCalculator {
|
|||
dailyStatBean.extras = JSON.stringify(extras);
|
||||
}
|
||||
}
|
||||
try {
|
||||
await this.upsertStat("stat_daily", this.monitorID, dailyKey,
|
||||
dailyData.up, dailyData.down, dailyData.avgPing,
|
||||
dailyData.minPing, dailyData.maxPing);
|
||||
} catch (error) {
|
||||
log.warn("uptime-calc", `Upsert failed for daily stat, falling back to R.store(): ${error.message}`);
|
||||
await R.store(dailyStatBean);
|
||||
}
|
||||
|
||||
let currentDate = this.getCurrentDate();
|
||||
|
||||
|
@ -326,8 +333,15 @@ class UptimeCalculator {
|
|||
hourlyStatBean.extras = JSON.stringify(extras);
|
||||
}
|
||||
}
|
||||
try {
|
||||
await this.upsertStat("stat_hourly", this.monitorID, hourlyKey,
|
||||
hourlyData.up, hourlyData.down, hourlyData.avgPing,
|
||||
hourlyData.minPing, hourlyData.maxPing);
|
||||
} catch (error) {
|
||||
log.warn("uptime-calc", `Upsert failed for hourly stat, falling back to R.store(): ${error.message}`);
|
||||
await R.store(hourlyStatBean);
|
||||
}
|
||||
}
|
||||
|
||||
// For migration mode, we don't need to store old hourly and minutely data, but we need 24-hour's minutely data
|
||||
// Run anyway for non-migration mode
|
||||
|
@ -345,8 +359,15 @@ class UptimeCalculator {
|
|||
minutelyStatBean.extras = JSON.stringify(extras);
|
||||
}
|
||||
}
|
||||
try {
|
||||
await this.upsertStat("stat_minutely", this.monitorID, divisionKey,
|
||||
minutelyData.up, minutelyData.down, minutelyData.avgPing,
|
||||
minutelyData.minPing, minutelyData.maxPing);
|
||||
} catch (error) {
|
||||
log.warn("uptime-calc", `Upsert failed for minutely stat, falling back to R.store(): ${error.message}`);
|
||||
await R.store(minutelyStatBean);
|
||||
}
|
||||
}
|
||||
|
||||
// No need to remove old data in migration mode
|
||||
if (!this.migrationMode) {
|
||||
|
@ -386,6 +407,11 @@ class UptimeCalculator {
|
|||
bean = R.dispense("stat_daily");
|
||||
bean.monitor_id = this.monitorID;
|
||||
bean.timestamp = timestamp;
|
||||
bean.up = 0;
|
||||
bean.down = 0;
|
||||
bean.ping = 0;
|
||||
bean.pingMin = 0;
|
||||
bean.pingMax = 0;
|
||||
}
|
||||
|
||||
this.lastDailyStatBean = bean;
|
||||
|
@ -411,6 +437,11 @@ class UptimeCalculator {
|
|||
bean = R.dispense("stat_hourly");
|
||||
bean.monitor_id = this.monitorID;
|
||||
bean.timestamp = timestamp;
|
||||
bean.up = 0;
|
||||
bean.down = 0;
|
||||
bean.ping = 0;
|
||||
bean.pingMin = 0;
|
||||
bean.pingMax = 0;
|
||||
}
|
||||
|
||||
this.lastHourlyStatBean = bean;
|
||||
|
@ -436,6 +467,11 @@ class UptimeCalculator {
|
|||
bean = R.dispense("stat_minutely");
|
||||
bean.monitor_id = this.monitorID;
|
||||
bean.timestamp = timestamp;
|
||||
bean.up = 0;
|
||||
bean.down = 0;
|
||||
bean.ping = 0;
|
||||
bean.pingMin = 0;
|
||||
bean.pingMax = 0;
|
||||
}
|
||||
|
||||
this.lastMinutelyStatBean = bean;
|
||||
|
@ -516,6 +552,65 @@ class UptimeCalculator {
|
|||
return dailyKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upsert stat data using database-specific logic to handle concurrent insertions
|
||||
* @param {string} table The stat table name (stat_daily, stat_hourly, stat_minutely)
|
||||
* @param {number} monitorId The monitor ID
|
||||
* @param {number} timestamp The timestamp key
|
||||
* @param {number} up Up count
|
||||
* @param {number} down Down count
|
||||
* @param {number} ping Average ping
|
||||
* @param {number} pingMin Minimum ping
|
||||
* @param {number} pingMax Maximum ping
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async upsertStat(table, monitorId, timestamp, up, down, ping, pingMin, pingMax) {
|
||||
// Import Database locally to avoid circular dependency
|
||||
const Database = require("./database");
|
||||
|
||||
// Check if database is initialized - dbConfig.type must exist and not be empty
|
||||
if (!Database.dbConfig || !Database.dbConfig.type) {
|
||||
log.warn("uptime-calc", `Database not initialized yet for ${table}, falling back to R.store()`);
|
||||
throw new Error("Database not initialized");
|
||||
}
|
||||
|
||||
const dbType = Database.dbConfig.type;
|
||||
|
||||
try {
|
||||
if (dbType === "sqlite") {
|
||||
await R.exec(`
|
||||
INSERT INTO ${table} (monitor_id, timestamp, up, down, ping, ping_min, ping_max)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(monitor_id, timestamp) DO UPDATE SET
|
||||
up = ?,
|
||||
down = ?,
|
||||
ping = ?,
|
||||
ping_min = ?,
|
||||
ping_max = ?
|
||||
`, [
|
||||
monitorId, timestamp, up, down, ping, pingMin, pingMax,
|
||||
up, down, ping, pingMin, pingMax
|
||||
]);
|
||||
} else if (dbType.endsWith("mariadb")) {
|
||||
await R.exec(`
|
||||
INSERT INTO ${table} (monitor_id, timestamp, up, down, ping, ping_min, ping_max)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
up = VALUES(up),
|
||||
down = VALUES(down),
|
||||
ping = VALUES(ping),
|
||||
ping_min = VALUES(ping_min),
|
||||
ping_max = VALUES(ping_max)
|
||||
`, [ monitorId, timestamp, up, down, ping, pingMin, pingMax ]);
|
||||
} else {
|
||||
throw new Error(`Unsupported database type: ${dbType}`);
|
||||
}
|
||||
} catch (error) {
|
||||
log.debug("uptime-calc", `Failed to upsert ${table} for monitor ${monitorId}: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert timestamp to key
|
||||
* @param {dayjs.Dayjs} datetime Datetime
|
||||
|
|
Loading…
Add table
Reference in a new issue