Ssynchronize push monitor heartbeats to api calls

Includes a 1s buffer time to allow the push url to be called before the monitor is checked
This commit is contained in:
Aram Akhavan
2022-03-28 14:28:50 -07:00
parent d39dc94496
commit 39df4eea92
4 changed files with 54 additions and 48 deletions

View File

@@ -173,7 +173,7 @@ class Monitor extends BeanModel {
let bean = R.dispense("heartbeat");
bean.monitor_id = this.id;
bean.time = R.isoDateTime(dayjs.utc());
bean.time = R.isoDateTimeMillis(dayjs.utc());
bean.status = DOWN;
if (this.isUpsideDown()) {
@@ -348,25 +348,30 @@ class Monitor extends BeanModel {
bean.msg = dnsMessage;
bean.status = UP;
} else if (this.type === "push") { // Type: Push
const time = R.isoDateTime(dayjs.utc().subtract(this.interval, "second"));
let heartbeatCount = await R.count("heartbeat", " monitor_id = ? AND time > ? ", [
this.id,
time
]);
log.debug("monitor", "heartbeatCount" + heartbeatCount + " " + time);
if (heartbeatCount <= 0) {
// Fix #922, since previous heartbeat could be inserted by api, it should get from database
previousBeat = await Monitor.getPreviousHeartbeat(this.id);
throw new Error("No heartbeat in the time window");
} else {
// No need to insert successful heartbeat for push type, so end here
retries = 0;
this.heartbeatInterval = setTimeout(beat, beatInterval * 1000);
return;
log.debug(`[${this.name}] Checking monitor at ${dayjs().format("YYYY-MM-DD HH:mm:ss.SSS")}`);
const bufferTime = 1000; // 1s buffer to accommodate clock differences
// Fix #922, since previous heartbeat could be inserted by api, it should get from database
previousBeat = await Monitor.getPreviousHeartbeat(this.id);
//If the previous beat was nonexistent, down or pending we use the regular
// beatInterval/retryInterval in the setTimeout further below
if (previousBeat) {
const msSinceLastBeat = dayjs.utc().valueOf() - dayjs.utc(previousBeat.time).valueOf();
log.debug(`[${this.name}] msSinceLastBeat = ${msSinceLastBeat}`);
if (previousBeat.status !== UP || msSinceLastBeat > beatInterval * 1000 + bufferTime) {
throw new Error("No heartbeat in the time window");
} else {
let timeout = beatInterval * 1000 - msSinceLastBeat;
if (timeout < 0) {
timeout = bufferTime;
} else {
timeout += bufferTime;
}
// No need to insert successful heartbeat for push type, so end here
retries = 0;
log.debug(`[${this.name}] timeout = ${timeout}`);
this.heartbeatInterval = setTimeout(beat, timeout);
return;
}
}
} else if (this.type === "steam") {
@@ -694,7 +699,7 @@ class Monitor extends BeanModel {
} else {
// Handle new monitor with only one beat, because the beat's duration = 0
let status = parseInt(await R.getCell("SELECT `status` FROM heartbeat WHERE monitor_id = ?", [monitorID]));
let status = parseInt(await R.getCell("SELECT `status` FROM heartbeat WHERE monitor_id = ?", [ monitorID ]));
if (status === UP) {
uptime = 1;