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 { EmbeddedMariaDB } = require("./embedded-mariadb");
|
||||||
const mysql = require("mysql2/promise");
|
const mysql = require("mysql2/promise");
|
||||||
const { Settings } = require("./settings");
|
const { Settings } = require("./settings");
|
||||||
const { UptimeCalculator } = require("./uptime-calculator");
|
|
||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const { SimpleMigrationServer } = require("./utils/simple-migration-server");
|
const { SimpleMigrationServer } = require("./utils/simple-migration-server");
|
||||||
const KumaColumnCompiler = require("./utils/knex/lib/dialects/mysql2/schema/mysql2-columncompiler");
|
const KumaColumnCompiler = require("./utils/knex/lib/dialects/mysql2/schema/mysql2-columncompiler");
|
||||||
|
@ -217,6 +216,7 @@ class Database {
|
||||||
dbConfig = {
|
dbConfig = {
|
||||||
type: "sqlite",
|
type: "sqlite",
|
||||||
};
|
};
|
||||||
|
Database.dbConfig = dbConfig; // Fix: Also set Database.dbConfig in catch block
|
||||||
}
|
}
|
||||||
|
|
||||||
let config = {};
|
let config = {};
|
||||||
|
@ -823,7 +823,8 @@ class Database {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
for (let date of dates) {
|
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();
|
let calculator = new UptimeCalculator();
|
||||||
calculator.monitorID = monitor.monitor_id;
|
calculator.monitorID = monitor.monitor_id;
|
||||||
calculator.setMigrationMode(true);
|
calculator.setMigrationMode(true);
|
||||||
|
|
|
@ -306,7 +306,14 @@ class UptimeCalculator {
|
||||||
dailyStatBean.extras = JSON.stringify(extras);
|
dailyStatBean.extras = JSON.stringify(extras);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await R.store(dailyStatBean);
|
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();
|
let currentDate = this.getCurrentDate();
|
||||||
|
|
||||||
|
@ -326,7 +333,14 @@ class UptimeCalculator {
|
||||||
hourlyStatBean.extras = JSON.stringify(extras);
|
hourlyStatBean.extras = JSON.stringify(extras);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await R.store(hourlyStatBean);
|
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
|
// For migration mode, we don't need to store old hourly and minutely data, but we need 24-hour's minutely data
|
||||||
|
@ -345,7 +359,14 @@ class UptimeCalculator {
|
||||||
minutelyStatBean.extras = JSON.stringify(extras);
|
minutelyStatBean.extras = JSON.stringify(extras);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await R.store(minutelyStatBean);
|
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
|
// No need to remove old data in migration mode
|
||||||
|
@ -386,6 +407,11 @@ class UptimeCalculator {
|
||||||
bean = R.dispense("stat_daily");
|
bean = R.dispense("stat_daily");
|
||||||
bean.monitor_id = this.monitorID;
|
bean.monitor_id = this.monitorID;
|
||||||
bean.timestamp = timestamp;
|
bean.timestamp = timestamp;
|
||||||
|
bean.up = 0;
|
||||||
|
bean.down = 0;
|
||||||
|
bean.ping = 0;
|
||||||
|
bean.pingMin = 0;
|
||||||
|
bean.pingMax = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lastDailyStatBean = bean;
|
this.lastDailyStatBean = bean;
|
||||||
|
@ -411,6 +437,11 @@ class UptimeCalculator {
|
||||||
bean = R.dispense("stat_hourly");
|
bean = R.dispense("stat_hourly");
|
||||||
bean.monitor_id = this.monitorID;
|
bean.monitor_id = this.monitorID;
|
||||||
bean.timestamp = timestamp;
|
bean.timestamp = timestamp;
|
||||||
|
bean.up = 0;
|
||||||
|
bean.down = 0;
|
||||||
|
bean.ping = 0;
|
||||||
|
bean.pingMin = 0;
|
||||||
|
bean.pingMax = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lastHourlyStatBean = bean;
|
this.lastHourlyStatBean = bean;
|
||||||
|
@ -436,6 +467,11 @@ class UptimeCalculator {
|
||||||
bean = R.dispense("stat_minutely");
|
bean = R.dispense("stat_minutely");
|
||||||
bean.monitor_id = this.monitorID;
|
bean.monitor_id = this.monitorID;
|
||||||
bean.timestamp = timestamp;
|
bean.timestamp = timestamp;
|
||||||
|
bean.up = 0;
|
||||||
|
bean.down = 0;
|
||||||
|
bean.ping = 0;
|
||||||
|
bean.pingMin = 0;
|
||||||
|
bean.pingMax = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lastMinutelyStatBean = bean;
|
this.lastMinutelyStatBean = bean;
|
||||||
|
@ -516,6 +552,65 @@ class UptimeCalculator {
|
||||||
return dailyKey;
|
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
|
* Convert timestamp to key
|
||||||
* @param {dayjs.Dayjs} datetime Datetime
|
* @param {dayjs.Dayjs} datetime Datetime
|
||||||
|
|
Loading…
Add table
Reference in a new issue