Merge pull request #1428 from kaysond/master

Synchronize push monitor heartbeats to api calls (fixes #1422)
This commit is contained in:
Louis Lam 2022-05-29 12:34:16 +08:00 committed by GitHub
commit 90fe25e8ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 38 deletions

44
package-lock.json generated
View file

@ -28,7 +28,7 @@
"chroma-js": "^2.1.2", "chroma-js": "^2.1.2",
"command-exists": "~1.2.9", "command-exists": "~1.2.9",
"compare-versions": "~3.6.0", "compare-versions": "~3.6.0",
"dayjs": "~1.10.8", "dayjs": "^1.11.0",
"express": "~4.17.3", "express": "~4.17.3",
"express-basic-auth": "~1.2.1", "express-basic-auth": "~1.2.1",
"favico.js": "^0.3.10", "favico.js": "^0.3.10",
@ -51,7 +51,7 @@
"prom-client": "~13.2.0", "prom-client": "~13.2.0",
"prometheus-api-metrics": "~3.2.1", "prometheus-api-metrics": "~3.2.1",
"qrcode": "~1.5.0", "qrcode": "~1.5.0",
"redbean-node": "0.1.3", "redbean-node": "0.1.4",
"socket.io": "~4.4.1", "socket.io": "~4.4.1",
"socket.io-client": "~4.4.1", "socket.io-client": "~4.4.1",
"socks-proxy-agent": "^6.1.1", "socks-proxy-agent": "^6.1.1",
@ -5768,9 +5768,9 @@
} }
}, },
"node_modules/dayjs": { "node_modules/dayjs": {
"version": "1.10.8", "version": "1.11.0",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.8.tgz", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.0.tgz",
"integrity": "sha512-wbNwDfBHHur9UOzNUjeKUOJ0fCb0a52Wx0xInmQ7Y8FstyajiV1NmK1e00cxsr9YrE9r7yAChE0VvpuY5Rnlow==" "integrity": "sha512-JLC809s6Y948/FuCZPm5IX8rRhQwOiyMb2TfVVQEixG7P8Lm/gt5S7yoQZmC8x1UehI9Pb7sksEt4xx14m+7Ug=="
}, },
"node_modules/debug": { "node_modules/debug": {
"version": "4.3.4", "version": "4.3.4",
@ -14096,15 +14096,15 @@
} }
}, },
"node_modules/redbean-node": { "node_modules/redbean-node": {
"version": "0.1.3", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/redbean-node/-/redbean-node-0.1.3.tgz", "resolved": "https://registry.npmjs.org/redbean-node/-/redbean-node-0.1.4.tgz",
"integrity": "sha512-itAouTnNK12QXy10DxScFRDv/R3Zt1sZw+tfUQCsBALxDDCNXVUdkNTgClouUwbTDG1YMQkeoD1Je9ujN7u3yg==", "integrity": "sha512-c1U6wnTeWS0c44tn9hkJWzjGgckLNJ8sN1E2bxnnnQsULOfvEVFLf8dLMjqhyyMrZ1L1mp8UvV4OfhRtH/ZrgQ==",
"dependencies": { "dependencies": {
"@types/node": "^14.17.7", "@types/node": "^14.18.12",
"await-lock": "^2.1.0", "await-lock": "^2.1.0",
"dayjs": "^1.10.6", "dayjs": "^1.11.0",
"glob": "^7.1.7", "glob": "^7.2.0",
"knex": "^0.95.9", "knex": "^0.95.15",
"lodash": "^4.17.21" "lodash": "^4.17.21"
} }
}, },
@ -21243,9 +21243,9 @@
"dev": true "dev": true
}, },
"dayjs": { "dayjs": {
"version": "1.10.8", "version": "1.11.0",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.8.tgz", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.0.tgz",
"integrity": "sha512-wbNwDfBHHur9UOzNUjeKUOJ0fCb0a52Wx0xInmQ7Y8FstyajiV1NmK1e00cxsr9YrE9r7yAChE0VvpuY5Rnlow==" "integrity": "sha512-JLC809s6Y948/FuCZPm5IX8rRhQwOiyMb2TfVVQEixG7P8Lm/gt5S7yoQZmC8x1UehI9Pb7sksEt4xx14m+7Ug=="
}, },
"debug": { "debug": {
"version": "4.3.4", "version": "4.3.4",
@ -27531,15 +27531,15 @@
} }
}, },
"redbean-node": { "redbean-node": {
"version": "0.1.3", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/redbean-node/-/redbean-node-0.1.3.tgz", "resolved": "https://registry.npmjs.org/redbean-node/-/redbean-node-0.1.4.tgz",
"integrity": "sha512-itAouTnNK12QXy10DxScFRDv/R3Zt1sZw+tfUQCsBALxDDCNXVUdkNTgClouUwbTDG1YMQkeoD1Je9ujN7u3yg==", "integrity": "sha512-c1U6wnTeWS0c44tn9hkJWzjGgckLNJ8sN1E2bxnnnQsULOfvEVFLf8dLMjqhyyMrZ1L1mp8UvV4OfhRtH/ZrgQ==",
"requires": { "requires": {
"@types/node": "^14.17.7", "@types/node": "^14.18.12",
"await-lock": "^2.1.0", "await-lock": "^2.1.0",
"dayjs": "^1.10.6", "dayjs": "^1.11.0",
"glob": "^7.1.7", "glob": "^7.2.0",
"knex": "^0.95.9", "knex": "^0.95.15",
"lodash": "^4.17.21" "lodash": "^4.17.21"
}, },
"dependencies": { "dependencies": {

View file

@ -79,7 +79,7 @@
"chroma-js": "^2.1.2", "chroma-js": "^2.1.2",
"command-exists": "~1.2.9", "command-exists": "~1.2.9",
"compare-versions": "~3.6.0", "compare-versions": "~3.6.0",
"dayjs": "~1.10.8", "dayjs": "^1.11.0",
"express": "~4.17.3", "express": "~4.17.3",
"express-basic-auth": "~1.2.1", "express-basic-auth": "~1.2.1",
"favico.js": "^0.3.10", "favico.js": "^0.3.10",
@ -102,7 +102,7 @@
"prom-client": "~13.2.0", "prom-client": "~13.2.0",
"prometheus-api-metrics": "~3.2.1", "prometheus-api-metrics": "~3.2.1",
"qrcode": "~1.5.0", "qrcode": "~1.5.0",
"redbean-node": "0.1.3", "redbean-node": "0.1.4",
"socket.io": "~4.4.1", "socket.io": "~4.4.1",
"socket.io-client": "~4.4.1", "socket.io-client": "~4.4.1",
"socks-proxy-agent": "^6.1.1", "socks-proxy-agent": "^6.1.1",

View file

@ -192,7 +192,7 @@ class Monitor extends BeanModel {
let bean = R.dispense("heartbeat"); let bean = R.dispense("heartbeat");
bean.monitor_id = this.id; bean.monitor_id = this.id;
bean.time = R.isoDateTime(dayjs.utc()); bean.time = R.isoDateTimeMillis(dayjs.utc());
bean.status = DOWN; bean.status = DOWN;
if (this.isUpsideDown()) { if (this.isUpsideDown()) {
@ -367,22 +367,33 @@ class Monitor extends BeanModel {
bean.msg = dnsMessage; bean.msg = dnsMessage;
bean.status = UP; bean.status = UP;
} else if (this.type === "push") { // Type: Push } else if (this.type === "push") { // Type: Push
const time = R.isoDateTime(dayjs.utc().subtract(this.interval, "second")); log.debug("monitor", `[${this.name}] Checking monitor at ${dayjs().format("YYYY-MM-DD HH:mm:ss.SSS")}`);
const bufferTime = 1000; // 1s buffer to accommodate clock differences
let heartbeatCount = await R.count("heartbeat", " monitor_id = ? AND time > ? ", [ if (previousBeat) {
this.id, const msSinceLastBeat = dayjs.utc().valueOf() - dayjs.utc(previousBeat.time).valueOf();
time
]);
log.debug("monitor", "heartbeatCount" + heartbeatCount + " " + time); log.debug("monitor", `[${this.name}] msSinceLastBeat = ${msSinceLastBeat}`);
if (heartbeatCount <= 0) { // If the previous beat was down or pending we use the regular
throw new Error("No heartbeat in the time window"); // beatInterval/retryInterval in the setTimeout further below
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("monitor", `[${this.name}] timeout = ${timeout}`);
this.heartbeatInterval = setTimeout(beat, timeout);
return;
}
} else { } else {
// No need to insert successful heartbeat for push type, so end here throw new Error("No heartbeat in the time window");
retries = 0;
this.heartbeatInterval = setTimeout(beat, beatInterval * 1000);
return;
} }
} else if (this.type === "steam") { } else if (this.type === "steam") {

View file

@ -59,7 +59,7 @@ router.get("/api/push/:pushToken", async (request, response) => {
let duration = 0; let duration = 0;
let bean = R.dispense("heartbeat"); let bean = R.dispense("heartbeat");
bean.time = R.isoDateTime(dayjs.utc()); bean.time = R.isoDateTimeMillis(dayjs.utc());
if (previousHeartbeat) { if (previousHeartbeat) {
isFirstBeat = false; isFirstBeat = false;
@ -67,6 +67,7 @@ router.get("/api/push/:pushToken", async (request, response) => {
duration = dayjs(bean.time).diff(dayjs(previousHeartbeat.time), "second"); duration = dayjs(bean.time).diff(dayjs(previousHeartbeat.time), "second");
} }
log.debug("router", `/api/push/ called at ${dayjs().format("YYYY-MM-DD HH:mm:ss.SSS")}`);
log.debug("router", "PreviousStatus: " + previousStatus); log.debug("router", "PreviousStatus: " + previousStatus);
log.debug("router", "Current Status: " + status); log.debug("router", "Current Status: " + status);