initial import server-manager

This commit is contained in:
2026-07-22 00:12:44 +02:00
parent 8354d94cbc
commit 57d63f5bf4
13 changed files with 172 additions and 60 deletions
+6 -1
View File
@@ -1,7 +1,12 @@
node_modules/
dist/
build/
.env
*.log
.env
*-state.json
.vscode/
.idea/
-10
View File
@@ -1,10 +0,0 @@
{
"usedPorts": [
7777,
7778
],
"usedQueryPorts": [
27015,
27016
]
}
-20
View File
@@ -1,20 +0,0 @@
{
"servers": [
{
"id": "srv-ba25028b",
"name": "[EU] druecktieR | Crimson",
"wrapperId": "wrp-8adcbbf2",
"port": 7777,
"queryPort": 27015,
"created": 1784578015578
},
{
"id": "srv-d70d5c3a",
"name": "[EU] druecktieR | Azure",
"wrapperId": "wrp-8adcbbf2",
"port": 7778,
"queryPort": 27016,
"created": 1784653753332
}
]
}
+15 -8
View File
@@ -1,14 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.QUERY_PORT_START = exports.GAME_PORT_START = exports.DEFAULT_DESIRED_SERVERS = exports.LIFECYCLE_CRASH_TIMEOUT = exports.LIFECYCLE_SCALE_COOLDOWN = exports.LIFECYCLE_SCALE_DOWN_THRESHOLD = exports.LIFECYCLE_MIN_UPTIME = exports.LIFECYCLE_STARTUP_GRACE_PERIOD = exports.LIFECYCLE_EMPTY_TIMEOUT = exports.LIFECYCLE_CHECK_INTERVAL = exports.RABBITMQ_URL = void 0;
exports.QUERY_PORT_START = exports.GAME_PORT_START = exports.DEFAULT_DESIRED_SERVERS = exports.LIFECYCLE_CRASH_RETENTION = exports.LIFECYCLE_CRASH_TIMEOUT = exports.LIFECYCLE_SCALE_COOLDOWN = exports.LIFECYCLE_STARTUP_GRACE_PERIOD = exports.LIFECYCLE_SCALE_DOWN_THRESHOLD = exports.LIFECYCLE_MIN_UPTIME = exports.LIFECYCLE_EMPTY_TIMEOUT = exports.LIFECYCLE_CHECK_INTERVAL = exports.RABBITMQ_URL = void 0;
exports.RABBITMQ_URL = "amqp://manager:gigi1337@192.168.1.74";
exports.LIFECYCLE_CHECK_INTERVAL = 10000;
exports.LIFECYCLE_EMPTY_TIMEOUT = 300000;
exports.LIFECYCLE_STARTUP_GRACE_PERIOD = 60000;
exports.LIFECYCLE_MIN_UPTIME = 300000;
exports.LIFECYCLE_SCALE_DOWN_THRESHOLD = 0.30;
exports.LIFECYCLE_SCALE_COOLDOWN = 60000;
exports.LIFECYCLE_CRASH_TIMEOUT = 30000;
// Lifecycle
exports.LIFECYCLE_CHECK_INTERVAL = 10000; // Alle 10 Sekunden prüfen
// Scale Down
exports.LIFECYCLE_EMPTY_TIMEOUT = 300000; // 5 Minuten leer
exports.LIFECYCLE_MIN_UPTIME = 600000; // 10 Minuten Mindestlaufzeit
exports.LIFECYCLE_SCALE_DOWN_THRESHOLD = 0.30; // Unter 30% Gesamtauslastung darf abgebaut werden
// Scale Up
exports.LIFECYCLE_STARTUP_GRACE_PERIOD = 60000; // 1 Minute Schutz nach Start
exports.LIFECYCLE_SCALE_COOLDOWN = 120000; // 2 Minuten zwischen Scale-Up Aktionen
// Crash Detection
exports.LIFECYCLE_CRASH_TIMEOUT = 120000; // 2 Minuten ohne Status -> Crash
exports.LIFECYCLE_CRASH_RETENTION = 300000; // 5 Minuten sichtbar nach Crash
// Default
exports.DEFAULT_DESIRED_SERVERS = 1;
// Ports
exports.GAME_PORT_START = 7777;
exports.QUERY_PORT_START = 27015;
+18 -7
View File
@@ -1,13 +1,24 @@
export const RABBITMQ_URL = "amqp://manager:gigi1337@192.168.1.74";
export const LIFECYCLE_CHECK_INTERVAL = 10000;
export const LIFECYCLE_EMPTY_TIMEOUT = 300000;
export const LIFECYCLE_STARTUP_GRACE_PERIOD = 60000;
export const LIFECYCLE_MIN_UPTIME = 300000;
export const LIFECYCLE_SCALE_DOWN_THRESHOLD = 0.30;
export const LIFECYCLE_SCALE_COOLDOWN = 60000;
export const LIFECYCLE_CRASH_TIMEOUT = 30000;
// Lifecycle
export const LIFECYCLE_CHECK_INTERVAL = 10000; // Alle 10 Sekunden prüfen
// Scale Down
export const LIFECYCLE_EMPTY_TIMEOUT = 300000; // 5 Minuten leer
export const LIFECYCLE_MIN_UPTIME = 600000; // 10 Minuten Mindestlaufzeit
export const LIFECYCLE_SCALE_DOWN_THRESHOLD = 0.30; // Unter 30% Gesamtauslastung darf abgebaut werden
// Scale Up
export const LIFECYCLE_STARTUP_GRACE_PERIOD = 60000; // 1 Minute Schutz nach Start
export const LIFECYCLE_SCALE_COOLDOWN = 120000; // 2 Minuten zwischen Scale-Up Aktionen
// Crash Detection
export const LIFECYCLE_CRASH_TIMEOUT = 120000; // 2 Minuten ohne Status -> Crash
export const LIFECYCLE_CRASH_RETENTION = 300000; // 5 Minuten sichtbar nach Crash
// Default
export const DEFAULT_DESIRED_SERVERS = 1;
// Ports
export const GAME_PORT_START = 7777;
export const QUERY_PORT_START = 27015;
+32 -3
View File
@@ -51,6 +51,19 @@ class ServerLifecycle {
logger.info("Server RUNNING:", server.name, "PID:", server.pid);
}
break;
case "RECOVERING":
if (Date.now() -
server.lastSeen
>
config_1.LIFECYCLE_CRASH_TIMEOUT) {
server.status =
"CRASHED";
server.crashedAt =
Date.now();
this.serverRegistry.update(server);
logger.error("Server-Recovery fehlgeschlagen:", server.name);
}
break;
case "RUNNING":
/*
Crash Detection
@@ -61,6 +74,8 @@ class ServerLifecycle {
config_1.LIFECYCLE_CRASH_TIMEOUT) {
server.status =
"CRASHED";
server.crashedAt =
Date.now();
this.serverRegistry.update(server);
logger.error("Server abgestürzt:", server.name);
break;
@@ -92,9 +107,22 @@ class ServerLifecycle {
}
break;
case "CRASHED":
if (!server.crashedAt) {
server.crashedAt =
Date.now();
this.serverRegistry.update(server);
logger.error("Server abgestürzt erkannt:", server.name);
break;
}
if (Date.now() -
server.crashedAt
>
config_1.LIFECYCLE_CRASH_RETENTION) {
logger.info("Entferne abgestürzten Server nach Grace-Zeit:", server.name);
this.serverRegistry.remove(server.id);
}
break;
}
}
/*
AKTIVE SERVER
@@ -102,7 +130,8 @@ class ServerLifecycle {
const activeServers = this.serverRegistry
.getAll()
.filter(server => server.status === "RUNNING" ||
server.status === "STARTING");
server.status === "STARTING" ||
server.status === "RECOVERING");
/*
SLOT AUSLASTUNG
*/
@@ -166,14 +195,14 @@ class ServerLifecycle {
const activeCount = this.serverRegistry
.getAll()
.filter(s => s.status === "RUNNING" ||
s.status === "STARTING")
s.status === "STARTING" ||
s.status === "RECOVERING")
.length;
if (activeCount <=
this.desiredServers) {
break;
}
logger.info("Stoppe leeren Server:", server.name);
logger.info("Stoppe leeren Server:", server.name);
this.serverManager.stopServer(server.id);
}
}
+38
View File
@@ -9,6 +9,7 @@ import {
LIFECYCLE_SCALE_DOWN_THRESHOLD,
LIFECYCLE_SCALE_COOLDOWN,
LIFECYCLE_CRASH_TIMEOUT,
LIFECYCLE_CRASH_RETENTION,
DEFAULT_DESIRED_SERVERS
} from "./config";
@@ -178,6 +179,9 @@ export class ServerLifecycle {
server.status =
"CRASHED";
server.crashedAt =
Date.now();
this.serverRegistry.update(
server
@@ -218,6 +222,9 @@ export class ServerLifecycle {
server.status =
"CRASHED";
server.crashedAt =
Date.now();
this.serverRegistry.update(
server
@@ -317,12 +324,43 @@ export class ServerLifecycle {
case "CRASHED":
if(!server.crashedAt){
server.crashedAt =
Date.now();
this.serverRegistry.update(
server
);
logger.error(
"Server abgestürzt erkannt:",
server.name
);
break;
}
if(
Date.now() -
server.crashedAt
>
LIFECYCLE_CRASH_RETENTION
){
logger.info(
"Entferne abgestürzten Server nach Grace-Zeit:",
server.name
);
this.serverRegistry.remove(
server.id
);
}
break;
+16 -4
View File
@@ -21,7 +21,7 @@ class ServerRegistry {
port: serverData.port,
queryPort: serverData.queryPort,
created: serverData.created,
status: "STARTING",
status: "RECOVERING",
players: 0,
maxPlayers: 0,
lastSeen: Date.now()
@@ -96,9 +96,14 @@ class ServerRegistry {
logger.debug("Server cleanly stopped:", server.name);
this.remove(server.id);
}
else if (server.status === "RUNNING") {
else if (server.status === "RUNNING" ||
server.status === "RECOVERING") {
server.status =
"CRASHED";
if (!server.crashedAt) {
server.crashedAt =
Date.now();
}
this.servers.set(server.id, server);
logger.warn("Server crashed:", server.name);
}
@@ -117,7 +122,9 @@ class ServerRegistry {
server.lastSeen =
Date.now();
const oldStatus = server.status;
if (srv.alive) {
if (srv.alive && server.status !== "STOPPING") {
server.crashedAt =
undefined;
if (!server.startedAt) {
server.startedAt =
srv.started;
@@ -125,9 +132,14 @@ class ServerRegistry {
server.status =
"RUNNING";
}
else if (server.status === "RUNNING") {
else if (server.status === "RUNNING" ||
server.status === "RECOVERING") {
server.status =
"CRASHED";
if (!server.crashedAt) {
server.crashedAt =
Date.now();
}
}
if (oldStatus !== server.status) {
logger.debug("Status change:", server.name, oldStatus, "->", server.status);
+19
View File
@@ -42,6 +42,8 @@ export interface ServerInfo {
startedAt?:number;
crashedAt?:number;
lastSeen:number;
@@ -357,6 +359,13 @@ export class ServerRegistry {
server.status =
"CRASHED";
if(!server.crashedAt){
server.crashedAt =
Date.now();
}
this.servers.set(
server.id,
@@ -416,6 +425,9 @@ export class ServerRegistry {
if(srv.alive && server.status !== "STOPPING"){
server.crashedAt =
undefined;
if(!server.startedAt){
server.startedAt =
@@ -435,6 +447,13 @@ export class ServerRegistry {
server.status =
"CRASHED";
if(!server.crashedAt){
server.crashedAt =
Date.now();
}
}
+6
View File
@@ -35,6 +35,8 @@ class ServerStatusManager {
return;
server.status =
"RUNNING";
server.crashedAt =
undefined;
if (!server.startedAt) {
server.startedAt =
Date.now();
@@ -48,6 +50,10 @@ class ServerStatusManager {
return;
server.status =
"CRASHED";
if (!server.crashedAt) {
server.crashedAt =
Date.now();
}
this.registry.update(server);
logger.info("Server stopped:", data.serverId);
}
+10
View File
@@ -160,6 +160,9 @@ export class ServerStatusManager {
server.status =
"RUNNING";
server.crashedAt =
undefined;
if(!server.startedAt){
@@ -221,6 +224,13 @@ export class ServerStatusManager {
server.status =
"CRASHED";
if(!server.crashedAt){
server.crashedAt =
Date.now();
}
+2
View File
@@ -76,6 +76,7 @@ class WebApi {
name: server.name,
status: server.status,
wrapperId: server.wrapperId,
pid: server.pid,
port: server.port,
queryPort: server.queryPort,
players: server.players,
@@ -95,6 +96,7 @@ class WebApi {
name: server.name,
status: server.status,
wrapperId: server.wrapperId,
pid: server.pid,
port: server.port,
queryPort: server.queryPort,
players: server.players,
+4 -1
View File
@@ -6,5 +6,8 @@
"wrapper",
"shared",
"dashboard"
]
],
"allowScripts": {
"esbuild@0.21.5": true
}
}