Feat: Handle maintenance in UptimeCalculator (#4406)

Co-authored-by: Frank Elsinga <frank@elsinga.de>
This commit is contained in:
Nelson Chan 2024-03-27 10:19:25 +08:00 committed by GitHub
parent 49b6dacb4d
commit b8858f4605
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 94 additions and 18 deletions

View file

@ -0,0 +1,26 @@
exports.up = function (knex) {
return knex.schema
.alterTable("stat_daily", function (table) {
table.text("extras").defaultTo(null).comment("Extra statistics during this time period");
})
.alterTable("stat_minutely", function (table) {
table.text("extras").defaultTo(null).comment("Extra statistics during this time period");
})
.alterTable("stat_hourly", function (table) {
table.text("extras").defaultTo(null).comment("Extra statistics during this time period");
});
};
exports.down = function (knex) {
return knex.schema
.alterTable("stat_daily", function (table) {
table.dropColumn("extras");
})
.alterTable("stat_minutely", function (table) {
table.dropColumn("extras");
})
.alterTable("stat_hourly", function (table) {
table.dropColumn("extras");
});
};

View file

@ -116,14 +116,23 @@ class UptimeCalculator {
]); ]);
for (let bean of minutelyStatBeans) { for (let bean of minutelyStatBeans) {
let key = bean.timestamp; let data = {
this.minutelyUptimeDataList.push(key, {
up: bean.up, up: bean.up,
down: bean.down, down: bean.down,
avgPing: bean.ping, avgPing: bean.ping,
minPing: bean.pingMin, minPing: bean.pingMin,
maxPing: bean.pingMax, maxPing: bean.pingMax,
}); };
if (bean.extras != null) {
data = {
...data,
...JSON.parse(bean.extras),
};
}
let key = bean.timestamp;
this.minutelyUptimeDataList.push(key, data);
} }
// Load hourly data from database (recent 30 days only) // Load hourly data from database (recent 30 days only)
@ -133,14 +142,22 @@ class UptimeCalculator {
]); ]);
for (let bean of hourlyStatBeans) { for (let bean of hourlyStatBeans) {
let key = bean.timestamp; let data = {
this.hourlyUptimeDataList.push(key, {
up: bean.up, up: bean.up,
down: bean.down, down: bean.down,
avgPing: bean.ping, avgPing: bean.ping,
minPing: bean.pingMin, minPing: bean.pingMin,
maxPing: bean.pingMax, maxPing: bean.pingMax,
}); };
if (bean.extras != null) {
data = {
...data,
...JSON.parse(bean.extras),
};
}
this.hourlyUptimeDataList.push(bean.timestamp, data);
} }
// Load daily data from database (recent 365 days only) // Load daily data from database (recent 365 days only)
@ -150,14 +167,22 @@ class UptimeCalculator {
]); ]);
for (let bean of dailyStatBeans) { for (let bean of dailyStatBeans) {
let key = bean.timestamp; let data = {
this.dailyUptimeDataList.push(key, {
up: bean.up, up: bean.up,
down: bean.down, down: bean.down,
avgPing: bean.ping, avgPing: bean.ping,
minPing: bean.pingMin, minPing: bean.pingMin,
maxPing: bean.pingMax, maxPing: bean.pingMax,
}); };
if (bean.extras != null) {
data = {
...data,
...JSON.parse(bean.extras),
};
}
this.dailyUptimeDataList.push(bean.timestamp, data);
} }
} }
@ -170,11 +195,6 @@ class UptimeCalculator {
async update(status, ping = 0) { async update(status, ping = 0) {
let date = this.getCurrentDate(); let date = this.getCurrentDate();
// Don't count MAINTENANCE into uptime
if (status === MAINTENANCE) {
return date;
}
let flatStatus = this.flatStatus(status); let flatStatus = this.flatStatus(status);
if (flatStatus === DOWN && ping > 0) { if (flatStatus === DOWN && ping > 0) {
@ -189,7 +209,12 @@ class UptimeCalculator {
let hourlyData = this.hourlyUptimeDataList[hourlyKey]; let hourlyData = this.hourlyUptimeDataList[hourlyKey];
let dailyData = this.dailyUptimeDataList[dailyKey]; let dailyData = this.dailyUptimeDataList[dailyKey];
if (flatStatus === UP) { if (status === MAINTENANCE) {
minutelyData.maintenance = minutelyData.maintenance ? minutelyData.maintenance + 1 : 1;
hourlyData.maintenance = hourlyData.maintenance ? hourlyData.maintenance + 1 : 1;
dailyData.maintenance = dailyData.maintenance ? dailyData.maintenance + 1 : 1;
} else if (flatStatus === UP) {
minutelyData.up += 1; minutelyData.up += 1;
hourlyData.up += 1; hourlyData.up += 1;
dailyData.up += 1; dailyData.up += 1;
@ -233,7 +258,7 @@ class UptimeCalculator {
} }
} }
} else { } else if (flatStatus === DOWN) {
minutelyData.down += 1; minutelyData.down += 1;
hourlyData.down += 1; hourlyData.down += 1;
dailyData.down += 1; dailyData.down += 1;
@ -263,6 +288,13 @@ class UptimeCalculator {
dailyStatBean.ping = dailyData.avgPing; dailyStatBean.ping = dailyData.avgPing;
dailyStatBean.pingMin = dailyData.minPing; dailyStatBean.pingMin = dailyData.minPing;
dailyStatBean.pingMax = dailyData.maxPing; dailyStatBean.pingMax = dailyData.maxPing;
{
// eslint-disable-next-line no-unused-vars
const { up, down, avgPing, minPing, maxPing, ...extras } = dailyData;
if (Object.keys(extras).length > 0) {
dailyStatBean.extras = JSON.stringify(extras);
}
}
await R.store(dailyStatBean); await R.store(dailyStatBean);
let hourlyStatBean = await this.getHourlyStatBean(hourlyKey); let hourlyStatBean = await this.getHourlyStatBean(hourlyKey);
@ -271,6 +303,13 @@ class UptimeCalculator {
hourlyStatBean.ping = hourlyData.avgPing; hourlyStatBean.ping = hourlyData.avgPing;
hourlyStatBean.pingMin = hourlyData.minPing; hourlyStatBean.pingMin = hourlyData.minPing;
hourlyStatBean.pingMax = hourlyData.maxPing; hourlyStatBean.pingMax = hourlyData.maxPing;
{
// eslint-disable-next-line no-unused-vars
const { up, down, avgPing, minPing, maxPing, ...extras } = hourlyData;
if (Object.keys(extras).length > 0) {
hourlyStatBean.extras = JSON.stringify(extras);
}
}
await R.store(hourlyStatBean); await R.store(hourlyStatBean);
let minutelyStatBean = await this.getMinutelyStatBean(divisionKey); let minutelyStatBean = await this.getMinutelyStatBean(divisionKey);
@ -279,6 +318,13 @@ class UptimeCalculator {
minutelyStatBean.ping = minutelyData.avgPing; minutelyStatBean.ping = minutelyData.avgPing;
minutelyStatBean.pingMin = minutelyData.minPing; minutelyStatBean.pingMin = minutelyData.minPing;
minutelyStatBean.pingMax = minutelyData.maxPing; minutelyStatBean.pingMax = minutelyData.maxPing;
{
// eslint-disable-next-line no-unused-vars
const { up, down, avgPing, minPing, maxPing, ...extras } = minutelyData;
if (Object.keys(extras).length > 0) {
minutelyStatBean.extras = JSON.stringify(extras);
}
}
await R.store(minutelyStatBean); await R.store(minutelyStatBean);
// Remove the old data // Remove the old data
@ -474,7 +520,7 @@ class UptimeCalculator {
flatStatus(status) { flatStatus(status) {
switch (status) { switch (status) {
case UP: case UP:
// case MAINTENANCE: case MAINTENANCE:
return UP; return UP;
case DOWN: case DOWN:
case PENDING: case PENDING:
@ -606,7 +652,11 @@ class UptimeCalculator {
avgPing = totalPing / total.up; avgPing = totalPing / total.up;
} }
uptimeData.uptime = total.up / (total.up + total.down); if (total.up + total.down === 0) {
uptimeData.uptime = 0;
} else {
uptimeData.uptime = total.up / (total.up + total.down);
}
uptimeData.avgPing = avgPing; uptimeData.avgPing = avgPing;
return uptimeData; return uptimeData;
} }