Beenden haengt nicht mehr, Update-Agent startet erst nach Bestaetigung
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:
@@ -120,7 +120,21 @@ namespace PolyTrader.App.Avalonia
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
// Geordnetes Herunterfahren der Module – erst nach dem Ende der Oberfläche.
|
// 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();
|
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
|
/// 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.
|
/// herunter. Aus jeder Seite aufrufbar – auch aus Modul-Seiten, die die App nicht kennen.
|
||||||
/// </summary>
|
/// </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;
|
if (ShutdownConfirmed || _shutdownDialogOpen) return;
|
||||||
_shutdownDialogOpen = true;
|
_shutdownDialogOpen = true;
|
||||||
@@ -111,6 +122,7 @@ namespace PolyTrader.App.Avalonia.Shell
|
|||||||
? await dlg.ShowDialog<bool>(_shell)
|
? await dlg.ShowDialog<bool>(_shell)
|
||||||
: await dlg.ShowDialog<bool>(new Window());
|
: await dlg.ShowDialog<bool>(new Window());
|
||||||
if (!confirmed) return;
|
if (!confirmed) return;
|
||||||
|
if (onConfirmed != null && !onConfirmed()) return;
|
||||||
|
|
||||||
ShutdownConfirmed = true;
|
ShutdownConfirmed = true;
|
||||||
if (global::Avalonia.Application.Current?.ApplicationLifetime
|
if (global::Avalonia.Application.Current?.ApplicationLifetime
|
||||||
|
|||||||
@@ -269,7 +269,12 @@ namespace PolyTrader.App.Avalonia.Views
|
|||||||
try { licenseKey = SecretProtection.Unprotect(settings?.LicenseKey ?? string.Empty); }
|
try { licenseKey = SecretProtection.Unprotect(settings?.LicenseKey ?? string.Empty); }
|
||||||
catch { /* siehe CheckForUpdateAsync */ }
|
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,
|
agentPath: agentPath,
|
||||||
projectId: dcOptions.ProjectSlug,
|
projectId: dcOptions.ProjectSlug,
|
||||||
channel: dcOptions.Channel,
|
channel: dcOptions.Channel,
|
||||||
@@ -278,12 +283,13 @@ namespace PolyTrader.App.Avalonia.Views
|
|||||||
currentVersion: BuildInfo.Version,
|
currentVersion: BuildInfo.Version,
|
||||||
exitCurrentApp: false,
|
exitCurrentApp: false,
|
||||||
waitForCurrentProcess: true,
|
waitForCurrentProcess: true,
|
||||||
waitTimeoutSeconds: 40,
|
waitTimeoutSeconds: 120,
|
||||||
licenseKey: licenseKey);
|
licenseKey: licenseKey);
|
||||||
|
|
||||||
// Derselbe Weg wie ein Klick auf "Beenden" - inklusive Sicherheitsabfrage. Der Agent
|
if (_uiHost is AvaloniaUiHost shell)
|
||||||
// wartet ohnehin per --wait-for-pid auf unser Prozessende.
|
shell.RequestShutdown(onConfirmed: launchAgent);
|
||||||
_uiHost.RequestShutdown();
|
else if (launchAgent())
|
||||||
|
_uiHost.RequestShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Account-Übersicht =====
|
// ===== Account-Übersicht =====
|
||||||
|
|||||||
Reference in New Issue
Block a user