Desktop beendet sich auf SIGTERM, statt bis zum SIGKILL weiterzulaufen
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s

#600: Die ConsoleLifetime des Hosts faengt SIGTERM ab und ruft StopApplication.
Die Avalonia-Oberflaeche hing nicht daran - Main wartete weiter auf sie, und
systemctl stop, Abmelden oder Herunterfahren endeten mit SIGKILL.

App.axaml.cs haengt AvaloniaUiHost.ShutdownFromHost an ApplicationStopping:
Die Oberflaeche schliesst sich ohne Sicherheitsabfrage (der Stopp von aussen ist
selbst die Anweisung), danach laeuft der geordnete Dienst-Stopp aus Program.Main.

Auf der Linux-VM geprueft: SIGTERM -> beendet nach 1 s, "Dienste in 0,1 s beendet";
Gegenprobe "Beenden" in der Oberflaeche ebenso.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-09-15 11:09:43 +02:00
co-authored by Claude Opus 5
parent 23794304e6
commit cec8b91ebd
2 changed files with 30 additions and 0 deletions
+13
View File
@@ -2,7 +2,9 @@
using Avalonia; using Avalonia;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Threading;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using PolyTrader.App.Avalonia.Shell; using PolyTrader.App.Avalonia.Shell;
using PolyTrader.App.Avalonia.Views; using PolyTrader.App.Avalonia.Views;
@@ -50,6 +52,17 @@ namespace PolyTrader.App.Avalonia
// Schliessen der Shell laeuft ueber die Sicherheitsabfrage (wie bisher das X). // Schliessen der Shell laeuft ueber die Sicherheitsabfrage (wie bisher das X).
desktop.ShutdownMode = global::Avalonia.Controls.ShutdownMode.OnMainWindowClose; desktop.ShutdownMode = global::Avalonia.Controls.ShutdownMode.OnMainWindowClose;
// Stopp von aussen (SIGTERM, systemctl stop, Abmelden): Die ConsoleLifetime des Hosts faengt das
// Signal ab und ruft StopApplication - die Oberflaeche hing daran bisher nicht, Main wartete weiter
// auf sie, und der Prozess endete erst mit SIGKILL. Jetzt schliesst sie sich, danach laeuft der
// geordnete Stopp in Program.Main. Beim eigenen "Beenden" feuert ApplicationStopping erst, wenn die
// Oberflaeche schon zu ist; der Aufruf findet dann ShutdownConfirmed gesetzt vor.
Services.GetService<IHostApplicationLifetime>()?.ApplicationStopping.Register(() =>
{
try { Dispatcher.UIThread.Post(uiHost.ShutdownFromHost); }
catch { /* Dispatcher schon beendet - dann ist die Oberflaeche ohnehin zu */ }
});
// Erste Seite: die Startseite (frühere LauncherForm). // Erste Seite: die Startseite (frühere LauncherForm).
uiHost.ActivateMain(); uiHost.ActivateMain();
} }
@@ -102,6 +102,23 @@ namespace PolyTrader.App.Avalonia.Shell
/// </summary> /// </summary>
public void RequestShutdown() => RequestShutdown(onConfirmed: null); public void RequestShutdown() => RequestShutdown(onConfirmed: null);
/// <summary>
/// Schließt die Oberfläche OHNE Sicherheitsabfrage – nur für einen Stopp von außen (SIGTERM, systemctl
/// stop, Abmelden, Herunterfahren). Der ist selbst schon die ausdrückliche Anweisung; eine Abfrage, die
/// niemand beantwortet, hielt den Prozess bis zum SIGKILL am Leben. Nach dem Schließen läuft derselbe
/// geordnete Stopp der Dienste wie bei „Beenden" (Program.Main). Muss auf dem UI-Thread laufen.
/// </summary>
public void ShutdownFromHost()
{
if (ShutdownConfirmed) return;
ShutdownConfirmed = true;
if (global::Avalonia.Application.Current?.ApplicationLifetime
is global::Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.Shutdown();
}
}
/// <summary> /// <summary>
/// Wie <see cref="RequestShutdown()"/>, mit einem Schritt zwischen Bestätigung und Herunterfahren. /// Wie <see cref="RequestShutdown()"/>, mit einem Schritt zwischen Bestätigung und Herunterfahren.
/// </summary> /// </summary>