Beenden haengt nicht mehr, Update-Agent startet erst nach Bestaetigung
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s

Beim Updatetest auf der Linux-VM (14.09.2026) zeigte sich zweierlei:

1. Nach "Beenden" blieb der Prozess unbegrenzt stehen - Fenster offen, Port zu,
   Main-Thread in host.StopAsync(...).GetResult(), selbst SIGTERM ohne Wirkung.
   Betraf jedes Beenden der Oberflaeche, nicht nur den Update-Weg. Der Main-Thread
   traegt nach StartWithClassicDesktopLifetime noch Avalonias SynchronizationContext,
   dessen Dispatcher nicht mehr pumpt. Der Stopp laeuft jetzt per Task.Run ohne
   diesen Kontext, mit Obergrenze 45 s und Log der Dauer.

2. Der update-agent startete schon beim Klick auf "Installieren". Seine 40 s
   Wartefrist verstrichen waehrend Download und 10-Sekunden-Sperre, er brach ohne
   Update ab. Er startet jetzt erst nach bestaetigtem Beenden, Frist 120 s.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-09-14 11:52:06 +02:00
co-authored by Claude Opus 5
parent 0f18f562c7
commit 14c89aea7d
3 changed files with 39 additions and 7 deletions
+15 -1
View File
@@ -120,7 +120,21 @@ namespace PolyTrader.App.Avalonia
finally
{
// Geordnetes Herunterfahren der Module – erst nach dem Ende der Oberfläche.
host.StopAsync(TimeSpan.FromSeconds(30)).GetAwaiter().GetResult();
//
// NICHT direkt auf diesem Thread warten. Nach StartWithClassicDesktopLifetime trägt der
// Main-Thread noch den SynchronizationContext von Avalonia, dessen Dispatcher aber nicht
// mehr pumpt. Eine Fortsetzung im Stop-Pfad, die dorthin zurückwill, läuft dann nie - der
// Prozess blieb nach "Beenden" am 14.09.2026 auf der Linux-VM unbegrenzt stehen: Fenster
// offen, Port zu, Main-Thread in GetResult(), selbst SIGTERM ohne Wirkung. Damit griff
// auch kein Update, der update-agent wartete vergeblich auf das Prozessende.
// Task.Run startet ohne diesen Kontext; die Obergrenze fängt zusätzlich einen Dienst ab,
// der sein Token nicht beachtet.
var sw = System.Diagnostics.Stopwatch.StartNew();
var stop = Task.Run(() => host.StopAsync(TimeSpan.FromSeconds(30)));
if (stop.Wait(TimeSpan.FromSeconds(45)))
bootLog.Info($"Dienste in {sw.Elapsed.TotalSeconds:0.0} s beendet.");
else
bootLog.Warning("Dienste nach 45 s noch nicht beendet - Anwendung wird trotzdem geschlossen.");
host.Dispose();
}
}
@@ -100,7 +100,18 @@ namespace PolyTrader.App.Avalonia.Shell
/// Zeigt die Sicherheitsabfrage (Beenden-Schaltfläche 10 s gesperrt) und fährt bei Bestätigung
/// herunter. Aus jeder Seite aufrufbar – auch aus Modul-Seiten, die die App nicht kennen.
/// </summary>
public async void RequestShutdown()
public void RequestShutdown() => RequestShutdown(onConfirmed: null);
/// <summary>
/// Wie <see cref="RequestShutdown()"/>, mit einem Schritt zwischen Bestätigung und Herunterfahren.
/// </summary>
/// <param name="onConfirmed">
/// Läuft erst, wenn die Sicherheitsabfrage bestätigt ist - liefert er <c>false</c>, wird nicht
/// beendet. Für den Update-Weg: Der update-agent darf erst starten, wenn feststeht, dass die
/// Anwendung auch endet. Vorher lief seine Wartefrist schon während der 10-Sekunden-Sperre ab,
/// und nach „Abbrechen" wartete er ins Leere.
/// </param>
public async void RequestShutdown(Func<bool>? onConfirmed)
{
if (ShutdownConfirmed || _shutdownDialogOpen) return;
_shutdownDialogOpen = true;
@@ -111,6 +122,7 @@ namespace PolyTrader.App.Avalonia.Shell
? await dlg.ShowDialog<bool>(_shell)
: await dlg.ShowDialog<bool>(new Window());
if (!confirmed) return;
if (onConfirmed != null && !onConfirmed()) return;
ShutdownConfirmed = true;
if (global::Avalonia.Application.Current?.ApplicationLifetime
@@ -269,7 +269,12 @@ namespace PolyTrader.App.Avalonia.Views
try { licenseKey = SecretProtection.Unprotect(settings?.LicenseKey ?? string.Empty); }
catch { /* siehe CheckForUpdateAsync */ }
UpdateClient.LaunchUpdateAgent(
// Derselbe Weg wie ein Klick auf "Beenden" - inklusive Sicherheitsabfrage. Der Agent startet
// aber erst NACH deren Bestätigung: Am 14.09.2026 lief er schon beim Klick auf "Installieren"
// los, seine 40 s Wartefrist verstrichen während Download und 10-Sekunden-Sperre, und er
// brach ohne Update ab. 120 s decken das Herunterfahren ab (Dienste bis 45 s, siehe
// Program.Main); läuft die Anwendung danach noch, verändert der Agent nichts.
Func<bool> launchAgent = () => UpdateClient.LaunchUpdateAgent(
agentPath: agentPath,
projectId: dcOptions.ProjectSlug,
channel: dcOptions.Channel,
@@ -278,12 +283,13 @@ namespace PolyTrader.App.Avalonia.Views
currentVersion: BuildInfo.Version,
exitCurrentApp: false,
waitForCurrentProcess: true,
waitTimeoutSeconds: 40,
waitTimeoutSeconds: 120,
licenseKey: licenseKey);
// Derselbe Weg wie ein Klick auf "Beenden" - inklusive Sicherheitsabfrage. Der Agent
// wartet ohnehin per --wait-for-pid auf unser Prozessende.
_uiHost.RequestShutdown();
if (_uiHost is AvaloniaUiHost shell)
shell.RequestShutdown(onConfirmed: launchAgent);
else if (launchAgent())
_uiHost.RequestShutdown();
}
// ===== Account-Übersicht =====