Verstaendlicher Abbruch statt Absturz, wenn die Datenbankverbindung fehlt
Erster Befund aus dem Linux-Lauf auf der Test-VM (Roadmap A4a): Ohne konfigurierte Datenbank startete die Anwendung los und starb erst tief im DI-Aufbau mit einer unbehandelten ArgumentException und rund 50 Zeilen Stacktrace - "The string argument 'connectionString' cannot be empty", geworfen aus dem EF-Kern. Exitcode 134 (SIGABRT). Fuer den Serverbetrieb ist das gleich doppelt schlecht: Der Betreiber sieht nicht, was fehlt, und systemd startet den Dienst wegen Restart=on-failure alle zehn Sekunden neu. Im Journal stehen dann endlose Startversuche statt der Ursache. Genau dieser Zustand ist bei einer Erstinstallation der wahrscheinlichste - Software liegt da, Zugangsdaten sind noch nicht gesetzt. Behoben an drei Stellen: - Program.Main prueft die Verbindung, bevor der Host gebaut wird, und gibt aus, welcher Schluessel in welcher Datei erwartet wird, samt Beispiel und dem Hinweis, dass das Schema per "dotnet ef database update" angelegt wird (die Anwendung migriert nicht selbst). - Rueckgabewert 78 (EX_CONFIG aus den BSD-sysexits) statt eines Absturzes. - deploy/polytrader.service traegt RestartPreventExitStatus=78 - ein Konfigurationsfehler repariert sich durch Neustarts nicht, er wird dadurch nur unsichtbar. - AddCorePersistence wirft als zweite Verteidigungslinie eine InvalidOperationException mit derselben Aussage, falls jemand die Methode direkt aufruft. Der Connection-String wird dabei ueber dieselben Dateien und denselben Schluessel gelesen wie spaeter im Host, damit beide Wege nicht auseinanderlaufen koennen. Build gruen, 476 Tests gruen (Windows und Linux). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -35,6 +35,16 @@ namespace PolyTrader.App.Avalonia
|
||||
{
|
||||
private const string ServerSettingsPath = "server_settings.xml";
|
||||
|
||||
/// <summary>
|
||||
/// Rueckgabewert bei Konfigurationsfehlern. 78 ist EX_CONFIG aus den BSD-sysexits und
|
||||
/// damit ein etablierter Wert fuer "Konfiguration unbrauchbar". Wichtig fuer den
|
||||
/// Dienstbetrieb: <c>deploy/polytrader.service</c> traegt ihn in
|
||||
/// <c>RestartPreventExitStatus</c> ein, damit systemd bei einem Konfigurationsfehler
|
||||
/// NICHT im Zehn-Sekunden-Takt neu startet - ein fehlender Connection-String repariert
|
||||
/// sich durch Neustarts nicht.
|
||||
/// </summary>
|
||||
private const int ExitCodeConfigurationError = 78;
|
||||
|
||||
[STAThread]
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
@@ -49,6 +59,33 @@ namespace PolyTrader.App.Avalonia
|
||||
|
||||
var dcOptions = LoadDeploymentcenterOptions();
|
||||
|
||||
// Ohne Datenbankverbindung kann die Anwendung nichts Sinnvolles tun - jedes Repository
|
||||
// haengt daran. Bis zum 26.08.2026 lief sie trotzdem los und starb erst tief im
|
||||
// DI-Aufbau mit einer ArgumentException samt 50 Zeilen Stacktrace ("The string argument
|
||||
// 'connectionString' cannot be empty"). Auf einem Server ist das doppelt schlecht:
|
||||
// Der Betreiber sieht nicht, was fehlt, und systemd startet den Dienst wegen
|
||||
// Restart=on-failure endlos neu. Deshalb hier frueh und verstaendlich abbrechen.
|
||||
var connectionString = LoadDatabaseConnectionString();
|
||||
if (string.IsNullOrWhiteSpace(connectionString))
|
||||
{
|
||||
var err = Console.Error;
|
||||
err.WriteLine("FEHLER: Keine Datenbankverbindung konfiguriert.");
|
||||
err.WriteLine();
|
||||
err.WriteLine("Erwartet wird 'Database:MySqlConnectionString' in appsettings.Local.json");
|
||||
err.WriteLine($"neben der Programmdatei ({AppContext.BaseDirectory}).");
|
||||
err.WriteLine();
|
||||
err.WriteLine("Beispiel:");
|
||||
err.WriteLine("{");
|
||||
err.WriteLine(" \"Database\": {");
|
||||
err.WriteLine(" \"MySqlConnectionString\": \"Server=HOST;Port=3306;Database=polytrader;User ID=BENUTZER;Password=PASSWORT;\"");
|
||||
err.WriteLine(" }");
|
||||
err.WriteLine("}");
|
||||
err.WriteLine();
|
||||
err.WriteLine("Die Datei ist bewusst nicht versioniert (Zugangsdaten). Das Schema legt");
|
||||
err.WriteLine("'dotnet ef database update' an - die Anwendung migriert nicht selbst.");
|
||||
return ExitCodeConfigurationError;
|
||||
}
|
||||
|
||||
// Konstruktionsprüfung (--smoke-ui) testet Fensteraufbau, keine Lizenzlogik - dort
|
||||
// bewusst ALLE Module registrieren, sonst würde die Prüfung auf einem Build-Server
|
||||
// (nie lizenziert) still einen Großteil ihrer Abdeckung verlieren.
|
||||
@@ -113,6 +150,22 @@ namespace PolyTrader.App.Avalonia
|
||||
return options;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Liest den Connection-String, bevor der Generic Host existiert - fuer die fruehe
|
||||
/// Konfigurationspruefung in <see cref="Main"/>. Liest dieselben Dateien und denselben
|
||||
/// Schluessel wie der Host spaeter, damit beide nicht auseinanderlaufen koennen.
|
||||
/// </summary>
|
||||
internal static string LoadDatabaseConnectionString()
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(AppContext.BaseDirectory)
|
||||
.AddJsonFile("appsettings.json", optional: true)
|
||||
.AddJsonFile("appsettings.Local.json", optional: true)
|
||||
.Build();
|
||||
|
||||
return config["Database:MySqlConnectionString"] ?? string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Baut den Anwendungs-Host: Konfiguration, Master-Key, Persistenz, Core-Dienste und die
|
||||
/// aktiven Module. Kennt die Oberfläche nicht.
|
||||
|
||||
Reference in New Issue
Block a user