Modulkontexte an die maßgebliche Datenbank; Shell-Shutdown weiter untersucht

Zwei Befunde aus dem ersten Dauerbetrieb auf dem Testserver.

#487: Der Fix zu #389 hatte nur den Core auf DatabaseEndpoint umgestellt. Alle
vier Modulkontexte lasen die Konfiguration weiter selbst und landeten auf dem
Platzhalter aus EffectiveConnectionString, sobald die Datenbank nur in
settings.json steht - "Access denied for user 'root'@'localhost'", waehrend der
Core im selben Prozess sauber arbeitete. Gefunden 30 Sekunden nach dem ersten
Start des Dienstes; kein Test und kein --check hatte es gesehen, weil --check
nur die Core-Verbindung oeffnet.

Die Kontexte loesen DatabaseEndpoint jetzt ueber die IServiceProvider-Ueberladung
von AddDbContextFactory auf. Der Platzhalter meldet sich ausserdem nicht mehr als
root an, sondern als "KEINE-DATENBANK-KONFIGURIERT" - die alte Meldung sah nach
einem Rechteproblem aus, obwohl gar keine Verbindung konfiguriert war.

#396 traegt NICHT. Die Pruefung auf der VM zeigt: Das Signal kommt an, der
Handler laeuft (Logzeile steht), aber der Prozess bleibt stehen. Zwei Ursachen
sind dabei aufgedeckt und behoben worden, eine dritte ist offen:

1. Ueber Avalonia.Application.Current war die Lebensdauer aus dem Signal-Thread
   nicht erreichbar - der Handler lief ins Leere. Sie wird jetzt im Hauptthread
   erzeugt (SetupWithLifetime + lifetime.Start) und dem Handler mitgegeben.
2. Die Sicherheitsabfrage der Shell fing das Schliessen ab und wartete auf einen
   Klick, den bei einem Signal niemand macht. Ein Signal ist keine Frage; der
   Handler uebergeht die Abfrage jetzt ausdruecklich.
3. OFFEN: Der Dispatcher-Rueckruf wird nicht ausgefuehrt - weder die Erfolgs-
   noch die Fehlerzeile erscheint, obwohl beide protokolliert wuerden. Der
   UI-Thread nimmt die Nachricht offenbar nicht an.

Die Messpunkte bleiben im Code: ohne sie war von aussen nicht zu unterscheiden,
ob das Signal ankommt, ob die Lebensdauer fehlt oder ob der Rueckruf haengt.

404 Tests gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-09-05 13:23:16 +02:00
co-authored by Claude Opus 5
parent 3bccd90d97
commit b618efa9ce
7 changed files with 105 additions and 24 deletions
@@ -20,12 +20,23 @@ public static class ServiceCollectionExtensions
}
/// <summary>
/// Liefert den Connection-String oder – bei leerem Wert (z. B. fehlende appsettings.Local.json) –
/// einen unschädlichen Platzhalter, damit der DbContext-Optionsbau nicht wirft. Die App startet so
/// unabhängig von der DB; echte Queries schlagen erst bei tatsächlichem Zugriff fehl.
/// Liefert den Connection-String oder – bei leerem Wert – einen Platzhalter, damit der
/// DbContext-Optionsbau nicht wirft. Die App startet so unabhängig von der Datenbank; echte
/// Abfragen scheitern erst beim tatsächlichen Zugriff.
///
/// <para><b>Der Platzhalter meldet sich bewusst nicht mehr als <c>root</c> an.</b> Vorher
/// stand dort „User ID=root;Password=;", und eine fehlende Konfiguration führte damit zu
/// „Access denied for user 'root'@'localhost'" – einer Meldung, die nach einem Rechteproblem
/// aussieht, während in Wahrheit gar keine Verbindung konfiguriert war. Der Nutzername sagt
/// jetzt, was los ist. Ein Anmeldeversuch als Administrator des Datenbankservers ist ohnehin
/// das Letzte, was ein Platzhalter tun sollte.</para>
///
/// <para>Wer die maßgebliche Verbindung braucht, nimmt <see cref="Configuration.DatabaseEndpoint"/>;
/// diese Methode ist nur der Notnagel für den Optionsbau.</para>
/// </summary>
public static string EffectiveConnectionString(string? connectionString)
=> string.IsNullOrWhiteSpace(connectionString)
? "Server=localhost;Port=3306;Database=ibkrtrader;User ID=root;Password=;"
? "Server=localhost;Port=3306;Database=ibkrtrader;" +
"User ID=KEINE-DATENBANK-KONFIGURIERT;Password=;"
: connectionString;
}