feat: der Monitor fragt das Panel, wenn eine Abfrage nicht ausreicht
Deploy / check (push) Canceled after 0s
Deploy / deploy (push) Canceled after 0s

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:
2026-08-13 18:05:24 +02:00
parent bce75f8c65
commit d6124fc2cd
6 changed files with 326 additions and 1 deletions
+45 -1
View File
@@ -8,6 +8,7 @@ import { brandFooter, botStatusText } from '../runtime-settings.js';
import { brandEmbed } from '../embeds.js';
import { moduleEnabled } from '../modules.js';
import { tuning, tuningMs, everyTuned } from '../tuning.js';
import { panelStatus, panelEintrag, zustandText, lastText, startetNoch, gewolltAus } from '../panel.js';
const GREEN = 0x23a55a;
const RED = 0xf23f43;
@@ -257,8 +258,14 @@ export function buildServerEmbed(r) {
// nicht verlässlich, und dann stünde das Steuerzeichen wörtlich da.
kopf.push(`*${r.spielname.trim().slice(0, 200)}*`);
}
// Wenn GameDig nichts erreicht hat, das Panel aber sagt, dass der
// Container laeuft und noch startet: DAS ist die richtige Auskunft. Ein
// Modpack braucht Minuten bis zum ersten Spieler -- am ATM10 des
// Betreibers 306 Sekunden -- und ein rotes "Offline" waere in dieser Zeit
// schlicht falsch.
const ausPanel = r.online ? null : zustandText(r.panel);
kopf.push([
r.online ? '🟢 **Online**' : '🔴 **Offline**',
r.online ? '🟢 **Online**' : (ausPanel ?? '🔴 **Offline**'),
zugang.grund ? `🔒 ${zugang.grund}` : null,
r.online && r.ping != null ? `${r.ping} ms` : null,
].filter(Boolean).join(' · '));
@@ -276,6 +283,12 @@ export function buildServerEmbed(r) {
r.mods != null ? { name: 'Mods', value: String(r.mods), inline: true } : null,
]));
// Was nur das Panel weiss: was der Server gerade verbraucht.
{
const last = lastText(r.panel);
if (last) embed.addFields({ name: 'Auf dem Wirt', value: last });
}
if (r.online && r.playerNames.length > 0) {
embed.addFields({
name: `Wer drauf ist (${r.playerNames.length})`,
@@ -318,6 +331,31 @@ async function handleAlerts(client, r) {
alertState.set(r.id, { fails: 0, down: false, since: null });
return;
}
// KEIN ALARM, WENN DAS PANEL DEN ZUSTAND ERKLÄREN KANN.
//
// Das ist der eigentliche Gewinn der Anbindung. GameDig *fragt* einen
// Server; ein startender antwortet nicht, und nach zwei Fehlversuchen
// stünde hier eine Ausfallmeldung. Bei einem Modpack sind das jedes Mal
// Minuten Fehlalarm — am ATM10 des Betreibers 306 Sekunden bis zum ersten
// Spieler. Das Panel *sieht* den Container und weiß, dass er läuft und
// nur das Fertig-Merkmal noch nicht durch ist.
//
// Zwei Fälle, eine Behandlung: nichts tun. Der Zähler bleibt dabei
// ausdrücklich STEHEN statt zurückgesetzt zu werden, aus zwei Gründen:
//
// - Läuft die Gnadenfrist ab, ohne dass der Server fertig wird, greift
// `startetNoch` nicht mehr und der Alarm kommt sofort statt erst nach
// zwei weiteren Durchläufen.
// - Ein bereits gemeldeter Ausfall bleibt gemeldet. Sonst verschluckt
// ein Stopp im Panel die spätere „✅ wieder online"-Entwarnung, und im
// Alarm-Kanal bliebe ein 🚨 ohne Auflösung stehen.
//
// Und was NICHT unterdrückt wird: ein Absturz, ein OOM-Kill und ein
// fehlender Container. Das sind die Fälle, für die es den Kanal gibt —
// hier hilft das Panel dem Alarm, statt ihn zu ersetzen.
if (startetNoch(r.panel) || gewolltAus(r.panel)) return;
const fails = s.fails + 1;
if (!s.down && fails >= tuning('monitor_fails')) {
const channel = await client.channels.fetch(channelId).catch(() => null);
@@ -343,6 +381,12 @@ export async function monitorTick(client) {
const results = await Promise.all(servers.map(queryServer));
// Die Zusatzauskunft vom Panel: EINMAL je Durchlauf, nicht je Server.
// Sie ist optional -- ist nichts eingetragen oder antwortet das Panel
// nicht, bleibt `panel` schlicht null und alles läuft wie vorher.
const panelItems = await panelStatus();
for (const r of results) r.panel = panelEintrag(panelItems, r);
// Verlauf für die Web-Seite festhalten + Cache fürs API
for (const r of results) {
lastResults.set(r.id, { ...r, checkedAt: Date.now() });