fix(ui): prevent async void races and leak-on-exit
- task detail vm: LoadAsync now uses a per-call CancellationTokenSource so rapid TaskUpdated events can't race on _taskId / Subtasks / Tags; old subtask PropertyChanged handlers are torn down before Clear - task detail vm: async void event handlers (OnTaskUpdated, OnWorktreeUpdated, OnSubtaskPropertyChanged) wrap work in try/catch so thrown exceptions can't crash the Avalonia sync context - task detail vm: Clear cancels/disposes the load CTS so a late-arriving LoadAsync can't resurrect detail state after deselect - app: DisposeAsync the ServiceProvider in a finally after the classic desktop lifetime ends, so WorkerClient.DisposeAsync runs and the SignalR connection closes cleanly instead of being abandoned Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,8 +22,19 @@ sealed class Program
|
||||
var factory = services.GetRequiredService<SqliteConnectionFactory>();
|
||||
SchemaInitializer.Apply(factory);
|
||||
|
||||
BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
try
|
||||
{
|
||||
BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Dispose the container so WorkerClient.DisposeAsync runs —
|
||||
// cancels the retry loop and closes the SignalR connection cleanly
|
||||
// instead of abandoning it.
|
||||
try { services.DisposeAsync().AsTask().GetAwaiter().GetResult(); }
|
||||
catch { /* best effort on shutdown */ }
|
||||
}
|
||||
}
|
||||
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
|
||||
Reference in New Issue
Block a user