mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-11-23 23:04:04 +00:00
add graceful shutdown
This commit is contained in:
parent
f2af5bc064
commit
b3bff8d735
6 changed files with 98 additions and 12 deletions
11
package-lock.json
generated
11
package-lock.json
generated
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"name": "uptime-kuma",
|
"name": "uptime-kuma",
|
||||||
"requires": true,
|
"version": "1.0.4",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-validator-identifier": {
|
"@babel/helper-validator-identifier": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.5",
|
||||||
|
@ -1518,6 +1519,14 @@
|
||||||
"toidentifier": "1.0.0"
|
"toidentifier": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"http-graceful-shutdown": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-graceful-shutdown/-/http-graceful-shutdown-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-2vmU3kWOsZqZy4Kn4EZp00CF+6glpNNN/NAYJPkO9bnMX/D8sRl29TsxIu9Vgyo8ygtCWazWJp720zHfqhSdXg==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "^4.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"http-signature": {
|
"http-signature": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
"dayjs": "^1.10.4",
|
"dayjs": "^1.10.4",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
|
"http-graceful-shutdown": "^3.1.2",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"nodemailer": "^6.6.2",
|
"nodemailer": "^6.6.2",
|
||||||
"password-hash": "^1.2.2",
|
"password-hash": "^1.2.2",
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
|
console.log("Welcome to Uptime Kuma ")
|
||||||
|
console.log("Importing libraries")
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const app = express();
|
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
const server = http.createServer(app);
|
|
||||||
const { Server } = require("socket.io");
|
const { Server } = require("socket.io");
|
||||||
const io = new Server(server);
|
|
||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const {R} = require("redbean-node");
|
const {R} = require("redbean-node");
|
||||||
const passwordHash = require('./password-hash');
|
const passwordHash = require('./password-hash');
|
||||||
|
@ -12,12 +11,20 @@ const Monitor = require("./model/monitor");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const {getSettings} = require("./util-server");
|
const {getSettings} = require("./util-server");
|
||||||
const {Notification} = require("./notification")
|
const {Notification} = require("./notification")
|
||||||
|
const gracefulShutdown = require('http-graceful-shutdown');
|
||||||
|
const {sleep} = require("./util");
|
||||||
const args = require('args-parser')(process.argv);
|
const args = require('args-parser')(process.argv);
|
||||||
|
|
||||||
const version = require('../package.json').version;
|
const version = require('../package.json').version;
|
||||||
const hostname = args.host || "0.0.0.0"
|
const hostname = args.host || "0.0.0.0"
|
||||||
const port = args.port || 3001
|
const port = args.port || 3001
|
||||||
|
|
||||||
|
console.log("Version: " + version)
|
||||||
|
|
||||||
|
console.log("Creating express and socket.io instance")
|
||||||
|
const app = express();
|
||||||
|
const server = http.createServer(app);
|
||||||
|
const io = new Server(server);
|
||||||
app.use(express.json())
|
app.use(express.json())
|
||||||
|
|
||||||
let totalClient = 0;
|
let totalClient = 0;
|
||||||
|
@ -539,11 +546,11 @@ async function initDatabase() {
|
||||||
const path = './data/kuma.db';
|
const path = './data/kuma.db';
|
||||||
|
|
||||||
if (! fs.existsSync(path)) {
|
if (! fs.existsSync(path)) {
|
||||||
console.log("Copy Database")
|
console.log("Copying Database")
|
||||||
fs.copyFileSync("./db/kuma.db", path);
|
fs.copyFileSync("./db/kuma.db", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Connect to Database")
|
console.log("Connecting to Database")
|
||||||
|
|
||||||
R.setup('sqlite', {
|
R.setup('sqlite', {
|
||||||
filename: path
|
filename: path
|
||||||
|
@ -660,3 +667,72 @@ async function sendImportantHeartbeatList(socket, monitorID) {
|
||||||
|
|
||||||
socket.emit("importantHeartbeatList", monitorID, list)
|
socket.emit("importantHeartbeatList", monitorID, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const startGracefulShutdown = async () => {
|
||||||
|
console.log('Shutdown requested');
|
||||||
|
|
||||||
|
|
||||||
|
await (new Promise((resolve) => {
|
||||||
|
server.close(async function () {
|
||||||
|
console.log('Stopped Express.');
|
||||||
|
process.exit(0)
|
||||||
|
setTimeout(async () =>{
|
||||||
|
await R.close();
|
||||||
|
console.log("Stopped DB")
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}, 5000)
|
||||||
|
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
let noReject = true;
|
||||||
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
|
noReject = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
async function shutdownFunction(signal) {
|
||||||
|
console.log('Called signal: ' + signal);
|
||||||
|
|
||||||
|
console.log("Stopping all monitors")
|
||||||
|
for (let id in monitorList) {
|
||||||
|
let monitor = monitorList[id]
|
||||||
|
monitor.stop()
|
||||||
|
}
|
||||||
|
await sleep(2000)
|
||||||
|
|
||||||
|
console.log("Closing DB")
|
||||||
|
|
||||||
|
// Special handle, because tarn.js throw a promise reject that cannot be caught
|
||||||
|
while (true) {
|
||||||
|
noReject = true;
|
||||||
|
await R.close()
|
||||||
|
await sleep(2000)
|
||||||
|
|
||||||
|
if (noReject) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
console.log("Waiting...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("OK")
|
||||||
|
}
|
||||||
|
|
||||||
|
function finalFunction() {
|
||||||
|
console.log('Graceful Shutdown')
|
||||||
|
}
|
||||||
|
|
||||||
|
gracefulShutdown(server, {
|
||||||
|
signals: 'SIGINT SIGTERM',
|
||||||
|
timeout: 30000, // timeout: 30 secs
|
||||||
|
development: false, // not in dev mode
|
||||||
|
forceExit: true, // triggers process.exit() at the end of shutdown process
|
||||||
|
onShutdown: shutdownFunction, // shutdown function (async) - e.g. for cleanup DB, ...
|
||||||
|
finally: finalFunction // finally function (sync) - e.g. for logging
|
||||||
|
});
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function sleep(ms) {
|
exports.sleep = function (ms) {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ucfirst(str) {
|
exports.ucfirst = function (str) {
|
||||||
if (! str) {
|
if (! str) {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import {sleep} from "../../server/util";
|
const {sleep} = require("../../server/util")
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
|
|
|
@ -188,7 +188,7 @@
|
||||||
<input type="number" class="form-control" id="gotify-priority" v-model="notification.gotifyPriority" required min="0" max="10" step="1">
|
<input type="number" class="form-control" id="gotify-priority" v-model="notification.gotifyPriority" required min="0" max="10" step="1">
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-if="notification.type === 'slack'">
|
<template v-if="notification.type === 'slack'">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="slack-webhook-url" class="form-label">Slack Webhook URL</label>
|
<label for="slack-webhook-url" class="form-label">Slack Webhook URL</label>
|
||||||
|
@ -220,7 +220,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Modal } from 'bootstrap'
|
import { Modal } from 'bootstrap'
|
||||||
import { ucfirst } from "../../server/util";
|
const {ucfirst} = require("../../server/util")
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { useToast } from 'vue-toastification'
|
import { useToast } from 'vue-toastification'
|
||||||
import Confirm from "./Confirm.vue";
|
import Confirm from "./Confirm.vue";
|
||||||
|
@ -276,7 +276,7 @@ export default {
|
||||||
name: "",
|
name: "",
|
||||||
type: null,
|
type: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default set to Telegram
|
// Default set to Telegram
|
||||||
this.notification.type = "telegram"
|
this.notification.type = "telegram"
|
||||||
this.notification.gotifyPriority = 8
|
this.notification.gotifyPriority = 8
|
||||||
|
|
Loading…
Reference in a new issue