|
@@ -7,15 +7,18 @@ import { Logger } from '../../../common/util/logger.class';
|
|
|
import { Database, ServiceChangedStatus } from './database.class';
|
|
import { Database, ServiceChangedStatus } from './database.class';
|
|
|
import { Timer } from '../timer.class';
|
|
import { Timer } from '../timer.class';
|
|
|
|
|
|
|
|
-type Subscriber = { id: number; interval: number; conf: HttpCheckConfig; db: Database };
|
|
|
|
|
|
|
+type Subscriber = { id: number; interval: number; conf: HttpCheckConfig };
|
|
|
|
|
|
|
|
export class HttpCheckController {
|
|
export class HttpCheckController {
|
|
|
private subscriptions: Array<Subscriber> = [];
|
|
private subscriptions: Array<Subscriber> = [];
|
|
|
|
|
+ private db!: Database;
|
|
|
|
|
|
|
|
- constructor(db: Database) {
|
|
|
|
|
|
|
+ constructor() {
|
|
|
|
|
+ this.db = new Database();
|
|
|
(async () => {
|
|
(async () => {
|
|
|
try {
|
|
try {
|
|
|
- const configs = await db.getHttpCheckConfigs();
|
|
|
|
|
|
|
+ await this.db.open();
|
|
|
|
|
+ const configs = await this.db.getHttpCheckConfigs();
|
|
|
|
|
|
|
|
configs.forEach(async conf => {
|
|
configs.forEach(async conf => {
|
|
|
if (!conf) return;
|
|
if (!conf) return;
|
|
@@ -25,7 +28,7 @@ export class HttpCheckController {
|
|
|
|
|
|
|
|
process.nextTick(async () => {
|
|
process.nextTick(async () => {
|
|
|
Logger.info('[INFO] Initial HTTP Service Check for', conf.title, '...');
|
|
Logger.info('[INFO] Initial HTTP Service Check for', conf.title, '...');
|
|
|
- await this.timerTick(conf, sub.db);
|
|
|
|
|
|
|
+ await this.timerTick(conf);
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
} catch (err) {
|
|
} catch (err) {
|
|
@@ -48,38 +51,39 @@ export class HttpCheckController {
|
|
|
await this.unscheduleCheck(subscriber);
|
|
await this.unscheduleCheck(subscriber);
|
|
|
break;
|
|
break;
|
|
|
case ServiceChangedStatus.Rescheduled:
|
|
case ServiceChangedStatus.Rescheduled:
|
|
|
- await this.unscheduleCheck(subscriber);
|
|
|
|
|
- await this.scheduleCheck(conf);
|
|
|
|
|
|
|
+ await this.rescheduleCheck(conf, subscriber);
|
|
|
break;
|
|
break;
|
|
|
default:
|
|
default:
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private async scheduleCheck(conf: HttpCheckConfig) {
|
|
|
|
|
- const serverDB = new Database();
|
|
|
|
|
- await serverDB.open();
|
|
|
|
|
-
|
|
|
|
|
|
|
+ private async scheduleCheck(conf: HttpCheckConfig, log = true) {
|
|
|
let interval = Number(conf.interval);
|
|
let interval = Number(conf.interval);
|
|
|
if (Number.isNaN(interval)) interval = defaults.serviceChecks.interval;
|
|
if (Number.isNaN(interval)) interval = defaults.serviceChecks.interval;
|
|
|
|
|
|
|
|
- Logger.info(`[INFO] Starting HTTP Service Check Controller for "${conf.title}" with interval ${interval} seconds ...`);
|
|
|
|
|
- const id = Timer.instance.subscribe(interval, async () => await this.timerTick(conf, serverDB));
|
|
|
|
|
- const sub = { id, interval, conf, db: serverDB };
|
|
|
|
|
|
|
+ if (log) Logger.info(`[INFO] Starting HTTP Service Check Controller for "${conf.title}" with interval ${interval} seconds ...`);
|
|
|
|
|
+ const id = Timer.instance.subscribe(interval, async () => await this.timerTick(conf));
|
|
|
|
|
+ const sub = { id, interval, conf };
|
|
|
this.subscriptions.push(sub);
|
|
this.subscriptions.push(sub);
|
|
|
return sub;
|
|
return sub;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private async unscheduleCheck(sub?: Subscriber) {
|
|
|
|
|
|
|
+ private async rescheduleCheck(conf: HttpCheckConfig, sub?: Subscriber) {
|
|
|
|
|
+ Logger.info('[INFO] Rescheduling HTTP Service Check for', conf.title);
|
|
|
|
|
+ await this.unscheduleCheck(sub, false);
|
|
|
|
|
+ await this.scheduleCheck(conf, false);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private async unscheduleCheck(sub?: Subscriber, log = true) {
|
|
|
if (!sub) return;
|
|
if (!sub) return;
|
|
|
|
|
|
|
|
- Logger.info('[INFO] Removing HTTP Service Check for', sub.conf.title);
|
|
|
|
|
|
|
+ if (log) Logger.info('[INFO] Removing HTTP Service Check for', sub.conf.title);
|
|
|
Timer.instance.unsubscribe(sub.id);
|
|
Timer.instance.unsubscribe(sub.id);
|
|
|
- await sub.db.close();
|
|
|
|
|
this.subscriptions = this.subscriptions.filter(s => s.id !== sub.id);
|
|
this.subscriptions = this.subscriptions.filter(s => s.id !== sub.id);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private async timerTick(conf: HttpCheckConfig, db: Database) {
|
|
|
|
|
|
|
+ private async timerTick(conf: HttpCheckConfig) {
|
|
|
Logger.debug('[DEBUG] TICK', new Date(), JSON.stringify(conf));
|
|
Logger.debug('[DEBUG] TICK', new Date(), JSON.stringify(conf));
|
|
|
|
|
|
|
|
const now = new Date();
|
|
const now = new Date();
|
|
@@ -88,7 +92,7 @@ export class HttpCheckController {
|
|
|
responseType: 'text'
|
|
responseType: 'text'
|
|
|
};
|
|
};
|
|
|
try {
|
|
try {
|
|
|
- const current = await db.getHttpCheckConfigByID(conf.serverId ?? 0, conf.id);
|
|
|
|
|
|
|
+ const current = await this.db.getHttpCheckConfigByID(conf.serverId ?? 0, conf.id);
|
|
|
|
|
|
|
|
if (!current) {
|
|
if (!current) {
|
|
|
Logger.warn(`[WARN] HealthCheckConfig(${conf.id}) not found in Database but still scheduled in Timer!`);
|
|
Logger.warn(`[WARN] HealthCheckConfig(${conf.id}) not found in Database but still scheduled in Timer!`);
|
|
@@ -104,14 +108,14 @@ export class HttpCheckController {
|
|
|
const reg = new RegExp(check, 'i');
|
|
const reg = new RegExp(check, 'i');
|
|
|
if (!reg.test(responseText)) {
|
|
if (!reg.test(responseText)) {
|
|
|
Logger.debug(`[DEBUG] Regular expression /${check}/i not found in response`);
|
|
Logger.debug(`[DEBUG] Regular expression /${check}/i not found in response`);
|
|
|
- await db.insertHealthCheckData(current.id, now, HttpCheckStatus.CheckFailed, `Regular expression /${check}/i not found in response`);
|
|
|
|
|
|
|
+ await this.db.insertHealthCheckData(current.id, now, HttpCheckStatus.CheckFailed, `Regular expression /${check}/i not found in response`);
|
|
|
success = false;
|
|
success = false;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (success) {
|
|
if (success) {
|
|
|
Logger.debug(`[DEBUG] HTTP Service Check "${current.title}": OK.`);
|
|
Logger.debug(`[DEBUG] HTTP Service Check "${current.title}": OK.`);
|
|
|
- await db.insertHealthCheckData(current.id, now, HttpCheckStatus.OK, 'OK');
|
|
|
|
|
|
|
+ await this.db.insertHealthCheckData(current.id, now, HttpCheckStatus.OK, 'OK');
|
|
|
}
|
|
}
|
|
|
} catch (err) {
|
|
} catch (err) {
|
|
|
let log = false;
|
|
let log = false;
|
|
@@ -119,11 +123,11 @@ export class HttpCheckController {
|
|
|
// err.code = 'ECONNREFUSED' | 'ECONNABORTED' | 'ERR_BAD_REQUEST' | 'ERR_BAD_RESPONSE' | ...?
|
|
// err.code = 'ECONNREFUSED' | 'ECONNABORTED' | 'ERR_BAD_REQUEST' | 'ERR_BAD_RESPONSE' | ...?
|
|
|
try {
|
|
try {
|
|
|
if (err.code === 'ECONNABORTED') {
|
|
if (err.code === 'ECONNABORTED') {
|
|
|
- await db.insertHealthCheckData(conf.id, now, HttpCheckStatus.Timeout, err.message);
|
|
|
|
|
|
|
+ await this.db.insertHealthCheckData(conf.id, now, HttpCheckStatus.Timeout, err.message);
|
|
|
} else if (err.code && ['ERR_BAD_REQUEST', 'ERR_BAD_RESPONSE'].includes(err.code)) {
|
|
} else if (err.code && ['ERR_BAD_REQUEST', 'ERR_BAD_RESPONSE'].includes(err.code)) {
|
|
|
- await db.insertHealthCheckData(conf.id, now, HttpCheckStatus.RequestFailed, `${err.response?.status} ${err.response?.statusText}`);
|
|
|
|
|
|
|
+ await this.db.insertHealthCheckData(conf.id, now, HttpCheckStatus.RequestFailed, `${err.response?.status} ${err.response?.statusText}`);
|
|
|
} else {
|
|
} else {
|
|
|
- await db.insertHealthCheckData(conf.id, now, HttpCheckStatus.RequestFailed, err.message);
|
|
|
|
|
|
|
+ await this.db.insertHealthCheckData(conf.id, now, HttpCheckStatus.RequestFailed, err.message);
|
|
|
}
|
|
}
|
|
|
} catch (insertErr) {
|
|
} catch (insertErr) {
|
|
|
Logger.error(`[ERROR] Inserting HealthCheckData on Error failed:`, insertErr);
|
|
Logger.error(`[ERROR] Inserting HealthCheckData on Error failed:`, insertErr);
|
|
@@ -131,7 +135,7 @@ export class HttpCheckController {
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
try {
|
|
try {
|
|
|
- await db.insertHealthCheckData(conf.id, now, HttpCheckStatus.Unknown, new String(err).toString());
|
|
|
|
|
|
|
+ await this.db.insertHealthCheckData(conf.id, now, HttpCheckStatus.Unknown, new String(err).toString());
|
|
|
} catch (insertErr) {
|
|
} catch (insertErr) {
|
|
|
Logger.error(`[ERROR] Inserting HealthCheckData on Error failed:`, insertErr);
|
|
Logger.error(`[ERROR] Inserting HealthCheckData on Error failed:`, insertErr);
|
|
|
}
|
|
}
|
|
@@ -140,4 +144,9 @@ export class HttpCheckController {
|
|
|
if (log) Logger.error('[ERROR] HTTP Service Check failed:', err);
|
|
if (log) Logger.error('[ERROR] HTTP Service Check failed:', err);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ async close() {
|
|
|
|
|
+ if (!this.db) return;
|
|
|
|
|
+ await this.db.close();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|