Skip to content

Commit 8338f4a

Browse files
author
csu333
authored
Merge branch 'louislam:master' into master
2 parents ddcfd3a + 07d28d8 commit 8338f4a

3 files changed

Lines changed: 86 additions & 9 deletions

File tree

server/notification-providers/stackfield.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ class Stackfield extends NotificationProvider {
2525

2626
const baseURL = await Settings.get("primaryBaseURL");
2727
if (baseURL) {
28-
textMsg += `\n${baseURL + getMonitorRelativeURL(monitorJSON.id)}`;
28+
const urlPath = monitorJSON ? getMonitorRelativeURL(monitorJSON.id) : "/";
29+
textMsg += `\n${baseURL + urlPath}`;
2930
}
3031

3132
const data = {

server/uptime-calculator.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -361,12 +361,12 @@ class UptimeCalculator {
361361
log.debug("uptime_calc", "Remove old data");
362362
await R.exec("DELETE FROM stat_minutely WHERE monitor_id = ? AND timestamp < ?", [
363363
this.monitorID,
364-
this.getMinutelyKey(currentDate.subtract(this.statMinutelyKeepHour, "hour")),
364+
this.getMinutelyKey(currentDate.subtract(this.statMinutelyKeepHour, "hour"), false),
365365
]);
366366

367367
await R.exec("DELETE FROM stat_hourly WHERE monitor_id = ? AND timestamp < ?", [
368368
this.monitorID,
369-
this.getHourlyKey(currentDate.subtract(this.statHourlyKeepDay, "day")),
369+
this.getHourlyKey(currentDate.subtract(this.statHourlyKeepDay, "day"), false),
370370
]);
371371
}
372372

@@ -442,16 +442,17 @@ class UptimeCalculator {
442442
/**
443443
* Convert timestamp to minutely key
444444
* @param {dayjs.Dayjs} date The heartbeat date
445+
* @param {boolean} createIfMissing Whether to create a missing bucket, defaults to true
445446
* @returns {number} Timestamp
446447
*/
447-
getMinutelyKey(date) {
448+
getMinutelyKey(date, createIfMissing = true) {
448449
// Truncate value to minutes (e.g. 2021-01-01 12:34:56 -> 2021-01-01 12:34:00)
449450
date = date.startOf("minute");
450451

451452
// Convert to timestamp in second
452453
let divisionKey = date.unix();
453454

454-
if (!(divisionKey in this.minutelyUptimeDataList)) {
455+
if (createIfMissing && !(divisionKey in this.minutelyUptimeDataList)) {
455456
this.minutelyUptimeDataList.push(divisionKey, {
456457
up: 0,
457458
down: 0,
@@ -467,16 +468,17 @@ class UptimeCalculator {
467468
/**
468469
* Convert timestamp to hourly key
469470
* @param {dayjs.Dayjs} date The heartbeat date
471+
* @param {boolean} createIfMissing Whether to create a missing bucket, defaults to true
470472
* @returns {number} Timestamp
471473
*/
472-
getHourlyKey(date) {
474+
getHourlyKey(date, createIfMissing = true) {
473475
// Truncate value to hours (e.g. 2021-01-01 12:34:56 -> 2021-01-01 12:00:00)
474476
date = date.startOf("hour");
475477

476478
// Convert to timestamp in second
477479
let divisionKey = date.unix();
478480

479-
if (!(divisionKey in this.hourlyUptimeDataList)) {
481+
if (createIfMissing && !(divisionKey in this.hourlyUptimeDataList)) {
480482
this.hourlyUptimeDataList.push(divisionKey, {
481483
up: 0,
482484
down: 0,
@@ -492,15 +494,16 @@ class UptimeCalculator {
492494
/**
493495
* Convert timestamp to daily key
494496
* @param {dayjs.Dayjs} date The heartbeat date
497+
* @param {boolean} createIfMissing Whether to create a missing bucket, defaults to true
495498
* @returns {number} Timestamp
496499
*/
497-
getDailyKey(date) {
500+
getDailyKey(date, createIfMissing = true) {
498501
// Truncate value to start of day (e.g. 2021-01-01 12:34:56 -> 2021-01-01 00:00:00)
499502
// Considering if the user keep changing could affect the calculation, so use UTC time to avoid this problem.
500503
date = date.utc().startOf("day");
501504
let dailyKey = date.unix();
502505

503-
if (!this.dailyUptimeDataList[dailyKey]) {
506+
if (createIfMissing && !this.dailyUptimeDataList[dailyKey]) {
504507
this.dailyUptimeDataList.push(dailyKey, {
505508
up: 0,
506509
down: 0,

test/backend-test/test-uptime-calculator.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,79 @@ describe("Uptime Calculator", () => {
6868
assert.strictEqual(divisionKey, dayjs.utc("2023-08-12 20:46:00").unix());
6969
});
7070

71+
test("missing cleanup buckets are not created when createIfMissing is false", () => {
72+
let c2 = new UptimeCalculator();
73+
74+
c2.getMinutelyKey(dayjs.utc("2023-08-12 20:46:59"));
75+
c2.getHourlyKey(dayjs.utc("2023-08-12 20:46:59"));
76+
c2.getDailyKey(dayjs.utc("2023-08-12 20:46:59"));
77+
78+
let minutelyCleanupKey = c2.getMinutelyKey(dayjs.utc("2023-08-11 20:46:59"), false);
79+
let hourlyCleanupKey = c2.getHourlyKey(dayjs.utc("2023-07-13 20:46:59"), false);
80+
let dailyCleanupKey = c2.getDailyKey(dayjs.utc("2022-08-12 20:46:59"), false);
81+
82+
assert.strictEqual(c2.minutelyUptimeDataList.length(), 1);
83+
assert.strictEqual(c2.hourlyUptimeDataList.length(), 1);
84+
assert.strictEqual(c2.dailyUptimeDataList.length(), 1);
85+
assert.strictEqual(c2.minutelyUptimeDataList[minutelyCleanupKey], undefined);
86+
assert.strictEqual(c2.hourlyUptimeDataList[hourlyCleanupKey], undefined);
87+
assert.strictEqual(c2.dailyUptimeDataList[dailyCleanupKey], undefined);
88+
});
89+
90+
test("cleanup lookup should not create missing minutely/hourly buckets", () => {
91+
let startDate = dayjs.utc("2023-08-12 00:00:00");
92+
93+
// First test the broken version that creates missing buckets during cleanup lookup.
94+
let broken = new UptimeCalculator();
95+
let minutelyQueueLimit = broken.minutelyUptimeDataList.__limit;
96+
let hourlyQueueLimit = broken.hourlyUptimeDataList.__limit;
97+
let totalTicks = Math.max(minutelyQueueLimit, hourlyQueueLimit);
98+
99+
let minutelyEndDate = startDate;
100+
let hourlyEndDate = startDate;
101+
for (let tick = 0; tick < totalTicks; tick++) {
102+
minutelyEndDate = startDate.add(tick, "minute");
103+
hourlyEndDate = startDate.add(tick, "hour");
104+
105+
// Simulate normal key lookup that creates buckets.
106+
broken.getMinutelyKey(minutelyEndDate);
107+
broken.getHourlyKey(hourlyEndDate);
108+
109+
// Simulate pre-fix cleanup key lookup that accidentally creates missing buckets.
110+
broken.getMinutelyKey(minutelyEndDate.subtract(broken.statMinutelyKeepHour, "hour"));
111+
broken.getHourlyKey(hourlyEndDate.subtract(broken.statHourlyKeepDay, "day"));
112+
}
113+
114+
UptimeCalculator.currentDate = minutelyEndDate;
115+
assert.strictEqual(broken.getDataArray(minutelyQueueLimit, "minute").length, minutelyQueueLimit / 2);
116+
117+
UptimeCalculator.currentDate = hourlyEndDate;
118+
assert.strictEqual(broken.getDataArray(hourlyQueueLimit, "hour").length, hourlyQueueLimit / 2);
119+
120+
// Now test the fixed version that should not create missing buckets.
121+
let fixed = new UptimeCalculator();
122+
let fixedMinutelyTickDate = startDate;
123+
let fixedHourlyTickDate = startDate;
124+
for (let tick = 0; tick < totalTicks; tick++) {
125+
fixedMinutelyTickDate = startDate.add(tick, "minute");
126+
fixedHourlyTickDate = startDate.add(tick, "hour");
127+
128+
// Simulate normal key lookup that creates buckets.
129+
fixed.getMinutelyKey(fixedMinutelyTickDate);
130+
fixed.getHourlyKey(fixedHourlyTickDate);
131+
132+
// Simulate pre-fix cleanup key lookup that should not create missing buckets.
133+
fixed.getMinutelyKey(fixedMinutelyTickDate.subtract(fixed.statMinutelyKeepHour, "hour"), false);
134+
fixed.getHourlyKey(fixedHourlyTickDate.subtract(fixed.statHourlyKeepDay, "day"), false);
135+
}
136+
137+
UptimeCalculator.currentDate = minutelyEndDate;
138+
assert.strictEqual(fixed.getDataArray(minutelyQueueLimit, "minute").length, minutelyQueueLimit);
139+
140+
UptimeCalculator.currentDate = hourlyEndDate;
141+
assert.strictEqual(fixed.getDataArray(hourlyQueueLimit, "hour").length, hourlyQueueLimit);
142+
});
143+
71144
test("getDailyKey() returns correct timestamp for start of day", () => {
72145
let c2 = new UptimeCalculator();
73146
let dailyKey = c2.getDailyKey(dayjs.utc("2023-08-12 20:46:00"));

0 commit comments

Comments
 (0)