feat: der Monitor fragt das Panel, wenn eine Abfrage nicht ausreicht
gamedig FRAGT einen Server. Ein startendes Modpack antwortet nicht, und
nach zwei Fehlversuchen stand im Alarm-Kanal eine Ausfallmeldung, obwohl
niemand etwas kaputtgemacht hat -- am ATM10 des Betreibers gemessen jedes
Mal 306 Sekunden Fehlalarm.
Das d4rk_gameserver-Panel SIEHT den Container, statt ihn zu fragen. Neu
ist deshalb `src/panel.js`: Zustand, Fertig-Merkmal, RAM und CPU kommen
als Zusatzauskunft dazu, einmal je Durchlauf abgerufen und 20 Sekunden
zwischengespeichert.
Was das im Alarm-Kanal aendert:
startet gerade kein Alarm, aber nur innerhalb einer Gnadenfrist von
15 Minuten. Ohne diese Grenze fraesse die Anbindung
genau den Alarm, fuer den es sie gibt -- `bereit`
wird nie von allein wahr, ein haengender Start bliebe
sonst fuer immer stumm.
im Panel gestoppt kein Alarm (Code 0/143/137)
abgestuerzt ALARM, mit Code im Embed
OOM-Kill ALARM, und beim Namen genannt statt als Absturz
getarnt -- bei Modpacks die haeufigste Ursache
Container weg ALARM
Der Zaehler wird beim Unterdruecken NICHT zurueckgesetzt: ein bereits
gemeldeter Ausfall bleibt gemeldet, sonst verschluckt ein Stopp im Panel
die spaetere "wieder online"-Entwarnung und im Kanal bliebe ein Alarm
ohne Aufloesung stehen.
ES IST DURCHGEHEND OPTIONAL. Adresse und Zeichen stehen im Webinterface
unter "Server" und NICHT in der .env; ohne Eintrag -- und ebenso, wenn
das Panel nicht antwortet -- verhaelt sich der Monitor exakt wie vorher.
Das Zeichen darf nur lesen, damit auch ein verlorenes niemandem einen
Server stoppen kann.
`tools/panel-pruefen.mjs` prueft die Logik ohne Discord und ohne
Datenbank; deshalb laedt panel.js die Einstellungen erst beim Aufruf.
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
// Die Panel-Anbindung -- ohne Discord, ohne Datenbank, nur die Logik.
|
||||
//
|
||||
// Geprüft wird vor allem, was passieren muss, wenn das Panel NICHT da ist:
|
||||
// dann darf sich nichts anders verhalten als vorher. Eine Zusatzauskunft, die
|
||||
// den Monitor mit herunterreißt, wäre schlimmer als gar keine.
|
||||
//
|
||||
// node tools/panel-pruefen.mjs
|
||||
|
||||
import { panelEintrag, zustandText, lastText, startetNoch, gewolltAus, STARTGNADE_MS } from '../src/panel.js'
|
||||
|
||||
let fehler = 0
|
||||
const zeig = (gut, was, dazu = '') => {
|
||||
if (!gut) fehler++
|
||||
console.log(` ${gut ? 'ok ' : 'FEHL'} ${was}${dazu ? ' ' + dazu : ''}`)
|
||||
}
|
||||
|
||||
const items = [
|
||||
// So sieht ein Modpack in der Startphase aus: Container läuft, das
|
||||
// Fertig-Merkmal stand noch nicht im Protokoll, GameDig bekommt nichts.
|
||||
{ name: 'atm11-test', zustand: 'running', bereit: false, port: 26000,
|
||||
seit: Date.now() - 120_000, cpu: 187, kerne: 20, ram: 5_153_960_755, ram_grenze: 7_516_192_768 },
|
||||
{ name: 'nallheim', zustand: 'running', bereit: true, port: 26004,
|
||||
seit: Date.now() - 3_600_000, cpu: 20, kerne: 20, ram: 1_073_741_824, ram_grenze: 5_368_709_120 },
|
||||
{ name: 'alt', zustand: 'exited', bereit: false, port: 26010, code: 0, oom: false,
|
||||
seit: null, cpu: null, kerne: null, ram: null, ram_grenze: null },
|
||||
]
|
||||
|
||||
// Ein Start, der die Gnadenfrist gerissen hat -- der Fall, in dem die
|
||||
// Anbindung NICHT mehr beschwichtigen darf.
|
||||
const haengt = { ...items[0], seit: Date.now() - (STARTGNADE_MS + 60_000) }
|
||||
|
||||
console.log('=== Zuordnen')
|
||||
zeig(panelEintrag(items, { port: 26000 })?.name === 'atm11-test', 'über den Port')
|
||||
zeig(panelEintrag(items, { name: 'NALLHEIM' })?.name === 'nallheim', 'ersatzweise über den Namen, groß/klein egal')
|
||||
zeig(panelEintrag(items, { port: 9999 }) === null, 'unbekannter Port -> nichts')
|
||||
zeig(panelEintrag(null, { port: 26000 }) === null, 'ohne Panel-Daten -> nichts')
|
||||
zeig(panelEintrag([], { port: 26000 }) === null, 'leere Liste -> nichts')
|
||||
|
||||
console.log('')
|
||||
console.log('=== Was im Embed steht, wenn GameDig nichts erreicht')
|
||||
const startet = zustandText(items[0])
|
||||
zeig(/Startet gerade/.test(startet ?? ''), 'startender Server -> „Startet gerade"', startet)
|
||||
zeig(/2 min/.test(startet ?? ''), 'mit Dauer', startet)
|
||||
zeig(/Gestoppt/.test(zustandText(items[2]) ?? ''), 'gestoppter -> „Gestoppt"', zustandText(items[2]))
|
||||
zeig(zustandText(items[1]) === null, 'ein bereiter Server trägt hier nichts bei — da war GameDig schon erfolgreich')
|
||||
zeig(zustandText(null) === null, 'ohne Eintrag -> null, dann bleibt es beim schlichten „Offline"')
|
||||
|
||||
console.log('')
|
||||
console.log('=== Wann der Alarm UNTERDRÜCKT wird -- und wann nicht')
|
||||
zeig(startetNoch(items[0]) === true, 'startender Server in der Frist -> unterdrücken')
|
||||
zeig(startetNoch(items[1]) === false, 'ein fertiger Server ist kein Startvorgang')
|
||||
zeig(startetNoch(items[2]) === false, 'ein beendeter erst recht nicht')
|
||||
zeig(startetNoch(null) === false, 'ohne Panel -> nichts unterdrücken (Monitor wie vorher)')
|
||||
// Die wichtigste Zeile hier: `bereit` wird nie von allein wahr. Ohne diese
|
||||
// Grenze fräße die Anbindung genau den Alarm, für den es sie gibt.
|
||||
zeig(startetNoch(haengt) === false, 'nach der Gnadenfrist NICHT mehr unterdrücken -- sonst kommt der Alarm nie')
|
||||
zeig(/nicht fertig/.test(zustandText(haengt) ?? ''), 'und im Embed steht dann Klartext', zustandText(haengt))
|
||||
zeig(startetNoch({ ...items[0], seit: null }) === true, 'ohne Startzeit -> Nachsicht (kaputter Zeitstempel, kein hängender Server)')
|
||||
|
||||
const abgestuerzt = { ...items[2], code: 1 }
|
||||
const oomTot = { ...items[2], code: 137, oom: true }
|
||||
const altesPanel = { name: 'x', zustand: 'exited', bereit: false, port: 1 } // ohne code/oom
|
||||
zeig(gewolltAus(items[2]) === true, 'Code 0 -> jemand hat gestoppt, kein Alarm')
|
||||
zeig(gewolltAus({ ...items[2], code: 143 }) === true, 'Code 143 (SIGTERM) -> auch ein Stopp')
|
||||
zeig(gewolltAus(abgestuerzt) === false, 'Code 1 -> ABSTURZ, der Alarm muss durch')
|
||||
zeig(gewolltAus(oomTot) === false, 'OOM-Kill -> Alarm, auch bei Code 137')
|
||||
zeig(gewolltAus(altesPanel) === false, 'älteres Panel ohne `code` -> im Zweifel echter Ausfall')
|
||||
zeig(gewolltAus(items[0]) === false, 'ein laufender Server ist nicht "aus"')
|
||||
zeig(/Abgestürzt.*\(Code 1\)/.test(zustandText(abgestuerzt) ?? ''), 'Absturz steht mit Code im Embed', zustandText(abgestuerzt))
|
||||
zeig(/Speicher/.test(zustandText(oomTot) ?? ''), 'OOM wird benannt, nicht als Absturz getarnt', zustandText(oomTot))
|
||||
|
||||
console.log('')
|
||||
console.log('=== Last')
|
||||
const last = lastText(items[0])
|
||||
zeig(/4\.8 GB \/ 7\.0 GB/.test(last ?? ''), 'RAM mit Grenze', last)
|
||||
// 187 / 20 = 9.35, und toFixed(1) macht daraus 9.3 -- 9.35 liegt binär knapp
|
||||
// UNTER 9.35, also wird abgerundet. Hier steht der gemessene Wert, nicht der
|
||||
// erwartete; für eine Auslastungsanzeige ist das Zehntel ohnehin ohne Belang.
|
||||
zeig(/9\.3 % CPU/.test(last ?? ''), 'CPU als Anteil der MASCHINE, nicht Dockers 187 %', last)
|
||||
zeig(lastText(items[2]) === null, 'gestoppt -> keine Last')
|
||||
zeig(lastText(null) === null, 'ohne Eintrag -> nichts')
|
||||
|
||||
console.log('')
|
||||
console.log('=== Abschaltbarkeit')
|
||||
// Ohne Panel-Eintrag muss JEDE dieser Funktionen null liefern, sonst steht
|
||||
// im Embed plötzlich ein leeres Feld.
|
||||
zeig([zustandText(undefined), lastText(undefined), panelEintrag(undefined, {})].every((x) => x == null),
|
||||
'undefined überall -> überall null')
|
||||
|
||||
console.log('')
|
||||
console.log(fehler ? `${fehler} FEHLER` : 'alles grün')
|
||||
process.exitCode = fehler ? 1 : 0
|
||||
Reference in New Issue
Block a user