From 89d51555040672b9c601c46e2af15a22be6bfe95 Mon Sep 17 00:00:00 2001 From: Gadfly Date: Mon, 31 Mar 2025 17:34:52 +0800 Subject: [PATCH] refactor: improve auto fetch timer implementation using PeriodicTimer #792 #1121 Replace System.Threading.Timer with PeriodicTimer for auto fetch functionality to: - Handle cancellation gracefully during repository close - Avoid unhandled exceptions in timer callbacks --- src/ViewModels/Repository.cs | 37 ++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index 6ea41e04..90495af6 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -456,12 +456,13 @@ namespace SourceGit.ViewModels _selectedView = _histories; _selectedViewIndex = 0; - _autoFetchTimer = new Timer(AutoFetchImpl, null, 5000, 5000); + _ = StartAutoFetchAsync(); RefreshAll(); } public void Close() { + _isClosing = true; SelectedView = null; // Do NOT modify. Used to remove exists widgets for GC.Collect var settingsSerialized = JsonSerializer.Serialize(_settings, JsonCodeGen.Default.RepositorySettings); @@ -473,7 +474,7 @@ namespace SourceGit.ViewModels { // Ignore } - _autoFetchTimer.Dispose(); + _autoFetchTimer?.Dispose(); _autoFetchTimer = null; _settings = null; @@ -2511,7 +2512,34 @@ namespace SourceGit.ViewModels MatchedFilesForSearching = matched; } - private void AutoFetchImpl(object sender) + private async Task StartAutoFetchAsync() + { + _autoFetchTimer = new PeriodicTimer(TimeSpan.FromSeconds(5)); + + try + { + while (!_isClosing && await _autoFetchTimer.WaitForNextTickAsync()) + { + if (_isClosing) + break; + + try + { + await Task.Run(AutoFetchImpl); + } + catch (Exception) + { + // ignored + } + } + } + catch (OperationCanceledException) + { + // ignored + } + } + + private void AutoFetchImpl() { if (!_settings.EnableAutoFetch || _isAutoFetching) return; @@ -2579,7 +2607,8 @@ namespace SourceGit.ViewModels private List _visibleSubmodules = new List(); private bool _isAutoFetching = false; - private Timer _autoFetchTimer = null; + private PeriodicTimer _autoFetchTimer; + private volatile bool _isClosing = false; private DateTime _lastFetchTime = DateTime.MinValue; } }