Procházet zdrojové kódy

ServerConnector & HttpCheckController: no need for permanent db connection; removed HealthCheckDataProvider interface

Christian Kahlau před 2 roky
rodič
revize
6f15658d47

+ 6 - 3
server/src/ctrl/data-provider.interface.ts

@@ -1,8 +1,7 @@
-import { ServiceCheckData } from '../../../common/lib/http-check-data.module';
+import { HttpCheckData, HttpCheckStatus, ServiceCheckData } from '../../../common/lib/http-check-data.module';
 import { ServiceChangedStatus } from '../lib/service-changed-status.enum';
-import { HealthCheckDataProvider } from './health-check-data-provider.interface';
 
-export interface DataProvider extends HealthCheckDataProvider {
+export interface DataProvider {
   open(migrate?: boolean): Promise<void>;
   getAllServerConfigs(): Promise<Server[]>;
   insertServerData(serverID: number, data: ReducedData[]): Promise<void>;
@@ -20,4 +19,8 @@ export interface DataProvider extends HealthCheckDataProvider {
   deleteHealthCheckConfig(serverID: number, confID: number): Promise<boolean>;
   queryServiceCheckData(serverID: number, confID: number, from: Date, to: Date): Promise<ServiceCheckData[]>;
   queryServiceCheckLogs(serverID: number, confID: number, from: Date, to: Date): Promise<ServiceCheckData[]>;
+
+  getHttpCheckConfigByID: (serverID: number, configID: number) => Promise<HttpCheckConfig | null>;
+  insertHealthCheckData: (confID: number, time: Date, status: HttpCheckStatus, message: string) => Promise<HttpCheckData>;
+  getLastErrors: (confID: number, threshold: number) => Promise<ServiceCheckData[]>;
 }

+ 0 - 7
server/src/ctrl/health-check-data-provider.interface.ts

@@ -1,7 +0,0 @@
-import { HttpCheckData, HttpCheckStatus, ServiceCheckData } from '../../../common/lib/http-check-data.module';
-
-export interface HealthCheckDataProvider {
-  getHttpCheckConfigByID: (serverID: number, configID: number) => Promise<HttpCheckConfig | null>;
-  insertHealthCheckData: (confID: number, time: Date, status: HttpCheckStatus, message: string) => Promise<HttpCheckData>;
-  getLastErrors: (confID: number, threshold: number) => Promise<ServiceCheckData[]>;
-}

+ 20 - 14
server/src/ctrl/http-check-controller.class.ts

@@ -9,7 +9,6 @@ import { Logger } from '../../../common/util/logger.class';
 import { ServiceChangedStatus } from '../lib/service-changed-status.enum';
 import { Timer } from '../timer.class';
 import { FCMController } from './fcm-controller.class';
-import { HealthCheckDataProvider } from './health-check-data-provider.interface';
 import { MariaDBDatabase } from './mariadb-database.class';
 
 type Subscriber = { id: number; interval: number; conf: HttpCheckConfig };
@@ -17,14 +16,13 @@ type ContentCheckError = { type: 'contentCheck'; status: HttpCheckStatus; messag
 
 export class HttpCheckController {
   private subscriptions: Array<Subscriber> = [];
-  private db!: MariaDBDatabase;
 
-  constructor(pool: Pool) {
-    this.db = new MariaDBDatabase(pool);
+  constructor(private pool: Pool) {
+    const db = new MariaDBDatabase(pool);
     (async () => {
       try {
-        await this.db.open();
-        const configs = await this.db.getHttpCheckConfigs();
+        await db.open();
+        const configs = await db.getHttpCheckConfigs();
 
         for (const conf of configs) {
           if (!conf) continue;
@@ -33,12 +31,16 @@ export class HttpCheckController {
           this.scheduleCheck(conf);
 
           Logger.info('[INFO] Initial HTTP Service Check for', conf.title, '...');
-          await this.runCheck(conf, this.db);
+          await this.runCheck(conf);
         }
       } catch (err) {
         Logger.error('[FATAL] Initializing HttpCheckController failed:', err);
         Logger.error('[EXITING]');
         process.exit(1);
+      } finally {
+        try {
+          await db.close();
+        } catch (e) {}
       }
     })();
   }
@@ -67,7 +69,7 @@ export class HttpCheckController {
     if (Number.isNaN(interval)) interval = defaults.serviceChecks.interval;
 
     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.runCheck(conf, this.db));
+    const id = Timer.instance.subscribe(interval, async () => await this.runCheck(conf));
     const sub = { id, interval, conf };
     this.subscriptions.push(sub);
     return sub;
@@ -87,7 +89,7 @@ export class HttpCheckController {
     this.subscriptions = this.subscriptions.filter(s => s.id !== sub.id);
   }
 
-  public async runCheck(conf: HttpCheckConfig, db: HealthCheckDataProvider) {
+  public async runCheck(conf: HttpCheckConfig) {
     Logger.debug('[DEBUG] TICK', new Date(), JSON.stringify(conf));
 
     const now = new Date();
@@ -96,7 +98,11 @@ export class HttpCheckController {
       responseType: 'text'
     };
     let success = true;
+
+    const db = new MariaDBDatabase(this.pool);
     try {
+      await db.open();
+
       const id = conf.id;
       conf = (await db.getHttpCheckConfigByID(conf.serverId ?? 0, id)) as HttpCheckConfig;
 
@@ -160,7 +166,12 @@ export class HttpCheckController {
         log = true;
       }
       if (log) Logger.error('[ERROR] HTTP Service Check failed:', err);
+    } finally {
+      try {
+        await db.close();
+      } catch (e) {}
     }
+
     if (!success && conf.notify && !process.env.DEV_MODE) {
       try {
         const lastErrors = await db.getLastErrors(conf.id, conf.notifyThreshold + 1);
@@ -240,9 +251,4 @@ export class HttpCheckController {
     }
     Logger.debug(`[DEBUG] RegExp check /${check}/i successful ✔︎`);
   }
-
-  async close() {
-    if (!this.db) return;
-    await this.db.close();
-  }
 }

+ 16 - 11
server/src/ctrl/server-connector.class.ts

@@ -11,14 +11,13 @@ import { MariaDBDatabase } from './mariadb-database.class';
 
 export class ServerConnector {
   private subscriptions: Array<{ id: number; interval: number; server: Server }> = [];
-  private db!: MariaDBDatabase;
 
-  constructor(pool: Pool) {
-    this.db = new MariaDBDatabase(pool);
+  constructor(private pool: Pool) {
+    const db = new MariaDBDatabase(pool);
     (async () => {
       try {
-        await this.db.open();
-        const serverList = await this.db.getAllServerConfigs();
+        await db.open();
+        const serverList = await db.getAllServerConfigs();
 
         for (const server of serverList) {
           let interval = Number(server.config['syncInterval']);
@@ -35,6 +34,10 @@ export class ServerConnector {
         Logger.error('[FATAL] Initializing ServerConnector failed:', err);
         Logger.error('[EXITING]');
         process.exit(1);
+      } finally {
+        try {
+          await db.close();
+        } catch (e) {}
       }
     })();
   }
@@ -44,7 +47,10 @@ export class ServerConnector {
     if (process.env.DEV_MODE) return Logger.warn('[WARN] DEV_MODE active - sync inactive.');
 
     let trxHdl: number | undefined = undefined;
+    const db = new MariaDBDatabase(this.pool);
     try {
+      await db.open();
+
       // Start Transaction, receiving Data and a Transaction Handle
       let response = await axios.get(`http://${server.fqdn}:8890/`, { responseType: 'json' });
       trxHdl = response.data.hdl;
@@ -54,7 +60,7 @@ export class ServerConnector {
       const data: ReducedData[] = response.data.data.map((entry: any) => ({ ...entry, time: new Date(entry.time) }));
 
       // Process data in DB
-      await this.db.insertServerData(server.id, data);
+      await db.insertServerData(server.id, data);
 
       // Commit Transaction
       await axios.patch(`http://${server.fqdn}:8890/${trxHdl}`, null, { responseType: 'json' });
@@ -97,11 +103,10 @@ export class ServerConnector {
       }
 
       // if (!!db) await db.close();
+    } finally {
+      try {
+        await db.close();
+      } catch (e) {}
     }
   }
-
-  async close() {
-    if (!this.db) return;
-    await this.db.close();
-  }
 }

+ 2 - 8
server/src/index.ts

@@ -54,14 +54,6 @@ let connectionPool: Pool;
 async function exitGracefully(...args: any[]) {
   Logger.info(`[EXITING] Graceful exit, received ${JSON.stringify(args)}`);
   try {
-    Logger.info(`[EXITING] Tear down ServerConnector ...`);
-    if (pool) {
-      await pool.serverConnector.close();
-
-      Logger.info(`[EXITING] Tear down HttpCheckController ...`);
-      await pool.httpChecks.close();
-    }
-
     if (mig) {
       Logger.info(`[EXITING] Tear down MariaDBImporter instance ...`);
       await mig.close();
@@ -76,5 +68,7 @@ async function exitGracefully(...args: any[]) {
     Logger.error(`[ERROR] Tear down sequence failed:`, err);
     process.exit(2);
   }
+
+  Logger.info(`[EXITING] Tear down sequence succeeded. exiting.`);
   process.exit(0);
 }

+ 1 - 52
server/src/webhdl/services-api-handler.class.ts

@@ -1,10 +1,9 @@
 import { RouterOptions, json } from 'express';
 
-import { HttpCheckData, HttpCheckStatus, ServiceCheckData, ServiceCheckDataEntry } from '../../../common/lib/http-check-data.module';
+import { ServiceCheckData } from '../../../common/lib/http-check-data.module';
 import { HttpStatusException } from '../../../common/lib/http-status.exception';
 
 import { ControllerPool } from '../ctrl/controller-pool.interface';
-import { HealthCheckDataProvider } from '../ctrl/health-check-data-provider.interface';
 import { ServiceChangedStatus } from '../lib/service-changed-status.enum';
 import { WebHandler } from './web-handler.base';
 
@@ -125,19 +124,6 @@ export class ServicesAPIHandler extends WebHandler {
         next(err);
       }
     });
-
-    this.router.post('/test', async (req, res, next) => {
-      try {
-        const config = req.body as HttpCheckConfig;
-        const mockDB = new HealthCheckDatabaseMock(config);
-
-        await this.ctrlPool.httpChecks.runCheck(config, mockDB);
-
-        res.send(mockDB.log);
-      } catch (err) {
-        next(err);
-      }
-    });
   }
 
   private validateNumber(id: string, field: string) {
@@ -150,40 +136,3 @@ export class ServicesAPIHandler extends WebHandler {
     return num;
   }
 }
-
-class HealthCheckDatabaseMock implements HealthCheckDataProvider {
-  public log: HttpCheckData[] = [];
-
-  constructor(private config: HttpCheckConfig) {}
-
-  async getHttpCheckConfigByID(serverID: number, configID: number) {
-    return this.config;
-  }
-  async insertHealthCheckData(confID: number, time: Date, status: HttpCheckStatus, message: string) {
-    const logEntry = { configId: confID, id: new Date().getTime(), time, status, message };
-    this.log.push(logEntry);
-    return logEntry;
-  }
-  async getLastErrors(confID: number, threshold: number) {
-    if (this.log.length === 0) return [];
-
-    const mapByTimestamp = new Map<number, ServiceCheckDataEntry[]>();
-    mapByTimestamp.set(this.log[0].time.getTime(), this.log);
-
-    const errors: ServiceCheckData[] = [];
-    for (const entry of mapByTimestamp.entries()) {
-      const time = entry[0];
-      const data = entry[1];
-
-      const errorData = data.filter(d => d.status !== HttpCheckStatus.OK);
-      if (!errorData.length) break;
-
-      errors.push({
-        time: new Date(time),
-        data: errorData
-      });
-    }
-
-    return errors;
-  }
-}