From 118afd20efcb54d9db2887d2d0a51e86c41c8a53 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 04:58:16 +0000 Subject: [PATCH 1/2] Initial plan From 04b97904677ee669d61f763ced25cb8f5fb84ea1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Oct 2025 05:04:13 +0000 Subject: [PATCH 2/2] Store and await indexing task to prevent incomplete program indexing Co-authored-by: Jack251970 <53996452+Jack251970@users.noreply.github.com> --- Plugins/Flow.Launcher.Plugin.Program/Main.cs | 66 ++++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index 0258a10d2c7..ce9e5dd03cb 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -31,6 +31,9 @@ public class Main : ISettingProvider, IAsyncPlugin, IPluginI18n, IContextMenu, I internal static PluginInitContext Context { get; private set; } + private static Task _indexingTask; + private static readonly object _indexingTaskLock = new(); + private static readonly List emptyResults = []; private static readonly MemoryCacheOptions cacheOptions = new() { SizeLimit = 1560 }; @@ -78,6 +81,31 @@ public class Main : ISettingProvider, IAsyncPlugin, IPluginI18n, IContextMenu, I public async Task> QueryAsync(Query query, CancellationToken token) { + // Wait for initial indexing to complete if it's still running + Task indexingTask; + lock (_indexingTaskLock) + { + indexingTask = _indexingTask; + } + + if (indexingTask != null && !indexingTask.IsCompleted) + { + try + { + // Wait for indexing with a reasonable timeout to avoid blocking queries indefinitely + await Task.WhenAny(indexingTask, Task.Delay(TimeSpan.FromSeconds(30), token)).ConfigureAwait(false); + } + catch (OperationCanceledException) + { + // Query was cancelled, return empty results + return emptyResults.ToList(); + } + catch (Exception e) + { + Context.API.LogException(ClassName, "Error waiting for indexing to complete", e); + } + } + var result = await cache.GetOrCreateAsync(query.Search, async entry => { var resultList = await Task.Run(async () => @@ -277,11 +305,21 @@ static void MoveFile(string sourcePath, string destinationPath) if (cacheEmpty || _settings.LastIndexTime.AddHours(30) < DateTime.Now) { - _ = Task.Run(async () => + lock (_indexingTaskLock) { - await IndexProgramsAsync().ConfigureAwait(false); - WatchProgramUpdate(); - }); + _indexingTask = Task.Run(async () => + { + try + { + await IndexProgramsAsync().ConfigureAwait(false); + WatchProgramUpdate(); + } + catch (Exception e) + { + Context.API.LogException(ClassName, "Failed to complete program indexing", e); + } + }); + } } else { @@ -483,6 +521,26 @@ public async Task ReloadDataAsync() public void Dispose() { + // Wait for indexing to complete before disposing + Task indexingTask; + lock (_indexingTaskLock) + { + indexingTask = _indexingTask; + } + + if (indexingTask != null && !indexingTask.IsCompleted) + { + try + { + // Wait for indexing to complete with a reasonable timeout + indexingTask.Wait(TimeSpan.FromSeconds(10)); + } + catch (Exception e) + { + Context?.API?.LogException(ClassName, "Error waiting for indexing during dispose", e); + } + } + Win32.Dispose(); } }