Add server monitoring module

This commit is contained in:
syuilo 2018-09-03 11:56:58 +09:00
parent 0b6c9323df
commit 3d3147c606
4 changed files with 116 additions and 1 deletions

View file

@ -10,6 +10,7 @@ import GuessingGameModule from './modules/guessing-game';
import KeywordModule from './modules/keyword'; import KeywordModule from './modules/keyword';
import WelcomeModule from './modules/welcome'; import WelcomeModule from './modules/welcome';
import TimerModule from './modules/timer'; import TimerModule from './modules/timer';
import ServerModule from './modules/server';
import * as request from 'request-promise-native'; import * as request from 'request-promise-native';
import IModule from './module'; import IModule from './module';
@ -34,7 +35,8 @@ promiseRetry(retry => {
new FortuneModule(), new FortuneModule(),
new GuessingGameModule(), new GuessingGameModule(),
new ReversiModule(), new ReversiModule(),
new TimerModule() new TimerModule(),
new ServerModule()
]; ];
if (config.keywordEnabled) modules.push(new KeywordModule()); if (config.keywordEnabled) modules.push(new KeywordModule());

106
src/modules/server/index.ts Normal file
View file

@ -0,0 +1,106 @@
import * as WebSocket from 'ws';
import from '../../ai';
import IModule from '../../module';
import serifs from '../../serifs';
import config from '../../config';
const ReconnectingWebSocket = require('../../../node_modules/reconnecting-websocket/dist/reconnecting-websocket-cjs.js');
export default class ServerModule implements IModule {
public readonly name = 'server';
private ai: ;
private connection?: any;
private recentStat: any;
private warned = false;
private lastWarnedAt: number;
/**
* 11
*/
private statsLogs: any[] = [];
public install = (ai: ) => {
this.ai = ai;
this.connection = new ReconnectingWebSocket(`${config.wsUrl}/server-stats`, [], {
WebSocket: WebSocket
});
this.connection.addEventListener('open', () => {
console.log('server-stats stream opened');
});
this.connection.addEventListener('close', () => {
console.log('server-stats stream closed');
this.connection.reconnect();
});
this.connection.addEventListener('message', message => {
const msg = JSON.parse(message.data);
this.onConnectionMessage(msg);
});
setInterval(() => {
this.statsLogs.unshift(this.recentStat);
if (this.statsLogs.length > 60) this.statsLogs.pop();
}, 1000);
setInterval(() => {
this.check();
}, 3000);
}
private check = () => {
const average = (arr) => arr.reduce((a, b) => a + b) / arr.length;
const cpuPercentages = this.statsLogs.map(s => s.cpu_usage * 100);
const cpuPercentage = average(cpuPercentages);
if (cpuPercentage >= 70) {
this.warn();
} else if (cpuPercentage <= 30) {
this.warned = false;
}
}
private onConnectionMessage = (msg: any) => {
switch (msg.type) {
case 'stats': {
this.onStats(msg.body);
break;
}
default:
break;
}
}
private onStats = async (stats: any) => {
this.recentStat = stats;
}
private warn = () => {
//#region 前に警告したときから一旦落ち着いた状態を経験していなければ警告しない
// 常に負荷が高いようなサーバーで無限に警告し続けるのを防ぐため
if (this.warned) return;
//#endregion
//#region 前の警告から1時間経っていない場合は警告しない
const now = Date.now();
if (this.lastWarnedAt != null) {
if (now - this.lastWarnedAt < (1000 * 60 * 60)) return;
}
this.lastWarnedAt = now;
//#endregion
this.ai.post({
text: serifs.server.cpu
});
this.warned = true;
}
}

View file

@ -228,5 +228,9 @@ export default {
tooLong: '長すぎます…', tooLong: '長すぎます…',
notify: (time, name) => name ? `${name}${time}経ちましたよ!` : `${time}経ちましたよ!` notify: (time, name) => name ? `${name}${time}経ちましたよ!` : `${time}経ちましたよ!`
},
server: {
cpu: 'サーバーの負荷が高そうです。大丈夫でしょうか...'
} }
}; };

View file

@ -46,6 +46,9 @@ Misskeyに24時間常駐している。AIなので睡眠は不要だが、たま
### なでなで ### なでなで
スキンシップ。(メッセージでのみ反応) スキンシップ。(メッセージでのみ反応)
### サーバー監視
サーバーの状態を監視し、負荷が高くなっているときは教えてくれます。
### ping ### ping
PONGを返します。生存確認にどうぞ PONGを返します。生存確認にどうぞ