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) {
let key = bean.timestamp;
this.minutelyUptimeDataList.push(key, {
let data = {
up: bean.up,
down: bean.down,
avgPing: bean.ping,
minPing: bean.pingMin,
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)
@ -133,14 +142,22 @@ class UptimeCalculator {
]);
for (let bean of hourlyStatBeans) {
let key = bean.timestamp;
this.hourlyUptimeDataList.push(key, {
let data = {
up: bean.up,
down: bean.down,
avgPing: bean.ping,
minPing: bean.pingMin,
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)
@ -150,14 +167,22 @@ class UptimeCalculator {
]);
for (let bean of dailyStatBeans) {
let key = bean.timestamp;
this.dailyUptimeDataList.push(key, {
let data = {
up: bean.up,
down: bean.down,
avgPing: bean.ping,
minPing: bean.pingMin,
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) {
let date = this.getCurrentDate();
// Don't count MAINTENANCE into uptime
if (status === MAINTENANCE) {
return date;
}
let flatStatus = this.flatStatus(status);
if (flatStatus === DOWN && ping > 0) {
@ -189,7 +209,12 @@ class UptimeCalculator {
let hourlyData = this.hourlyUptimeDataList[hourlyKey];
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;
hourlyData.up += 1;
dailyData.up += 1;
@ -233,7 +258,7 @@ class UptimeCalculator {
}
}
} else {
} else if (flatStatus === DOWN) {
minutelyData.down += 1;
hourlyData.down += 1;
dailyData.down += 1;
@ -263,6 +288,13 @@ class UptimeCalculator {
dailyStatBean.ping = dailyData.avgPing;
dailyStatBean.pingMin = dailyData.minPing;
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);
let hourlyStatBean = await this.getHourlyStatBean(hourlyKey);
@ -271,6 +303,13 @@ class UptimeCalculator {
hourlyStatBean.ping = hourlyData.avgPing;
hourlyStatBean.pingMin = hourlyData.minPing;
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);
let minutelyStatBean = await this.getMinutelyStatBean(divisionKey);
@ -279,6 +318,13 @@ class UptimeCalculator {
minutelyStatBean.ping = minutelyData.avgPing;
minutelyStatBean.pingMin = minutelyData.minPing;
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);
// Remove the old data
@ -474,7 +520,7 @@ class UptimeCalculator {
flatStatus(status) {
switch (status) {
case UP:
// case MAINTENANCE:
case MAINTENANCE:
return UP;
case DOWN:
case PENDING:
@ -606,7 +652,11 @@ class UptimeCalculator {
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;
return uptimeData;
}