mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
CherryPick Exception Optimize
This commit is contained in:
parent
fe859f6041
commit
f80ae3092e
6 changed files with 122 additions and 102 deletions
|
|
@ -157,7 +157,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
}
|
||||
|
||||
public static async Task<List<Result>> QueryForPlugin(PluginPair pair, Query query, CancellationToken token)
|
||||
public static async Task<List<Result>> QueryForPluginAsync(PluginPair pair, Query query, CancellationToken token)
|
||||
{
|
||||
var results = new List<Result>();
|
||||
try
|
||||
|
|
@ -171,7 +171,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
token.ThrowIfCancellationRequested();
|
||||
if (results == null)
|
||||
return results;
|
||||
return null;
|
||||
UpdatePluginMetadata(results, metadata, query);
|
||||
|
||||
metadata.QueryCount += 1;
|
||||
|
|
@ -184,10 +184,6 @@ namespace Flow.Launcher.Core.Plugin
|
|||
// null will be fine since the results will only be added into queue if the token hasn't been cancelled
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Exception($"|PluginManager.QueryForPlugin|Exception for plugin <{pair.Metadata.Name}> when query <{query}>", e);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="16.10.56" />
|
||||
<PackageReference Include="NLog.Schema" Version="4.7.0-rc1" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="4.9.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="4.7.0" />
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ using NLog;
|
|||
using NLog.Config;
|
||||
using NLog.Targets;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using JetBrains.Annotations;
|
||||
using NLog.Targets.Wrappers;
|
||||
using System.Runtime.ExceptionServices;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure.Logger
|
||||
{
|
||||
|
|
@ -23,11 +26,13 @@ namespace Flow.Launcher.Infrastructure.Logger
|
|||
}
|
||||
|
||||
var configuration = new LoggingConfiguration();
|
||||
var target = new FileTarget();
|
||||
configuration.AddTarget("file", target);
|
||||
target.FileName = CurrentLogDirectory.Replace(@"\", "/") + "/${shortdate}.txt";
|
||||
var fileTarget = new FileTarget();
|
||||
fileTarget.FileName = CurrentLogDirectory.Replace(@"\", "/") + "/${shortdate}.txt";
|
||||
|
||||
var fileTargetASyncWrapper = new AsyncTargetWrapper(fileTarget);
|
||||
configuration.AddTarget("file", fileTargetASyncWrapper);
|
||||
#if DEBUG
|
||||
var rule = new LoggingRule("*", LogLevel.Debug, target);
|
||||
var rule = new LoggingRule("*", LogLevel.Debug, fileTargetASyncWrapper);
|
||||
#else
|
||||
var rule = new LoggingRule("*", LogLevel.Info, target);
|
||||
#endif
|
||||
|
|
@ -50,13 +55,12 @@ namespace Flow.Launcher.Infrastructure.Logger
|
|||
return valid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
|
||||
public static void Exception(string className, string message, System.Exception exception, [CallerMemberName] string methodName = "")
|
||||
{
|
||||
{
|
||||
exception = exception.Demystify();
|
||||
#if DEBUG
|
||||
throw exception;
|
||||
ExceptionDispatchInfo.Capture(exception).Throw();
|
||||
#else
|
||||
var classNameWithMethod = CheckClassAndMessageAndReturnFullClassWithMethod(className, message, methodName);
|
||||
|
||||
|
|
@ -131,8 +135,9 @@ namespace Flow.Launcher.Infrastructure.Logger
|
|||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
public static void Exception(string message, System.Exception e)
|
||||
{
|
||||
e = e.Demystify();
|
||||
#if DEBUG
|
||||
throw e;
|
||||
ExceptionDispatchInfo.Capture(e).Throw();
|
||||
#else
|
||||
if (FormatValid(message))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,8 +19,10 @@ using Flow.Launcher.Plugin;
|
|||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using Flow.Launcher.Storage;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using System.Threading.Channels;
|
||||
using ISavable = Flow.Launcher.Plugin.ISavable;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Flow.Launcher.ViewModel
|
||||
{
|
||||
|
|
@ -110,7 +112,9 @@ namespace Flow.Launcher.ViewModel
|
|||
}
|
||||
|
||||
Log.Error("MainViewModel", "Unexpected ResultViewUpdate ends");
|
||||
};
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
void continueAction(Task t)
|
||||
{
|
||||
|
|
@ -118,7 +122,7 @@ namespace Flow.Launcher.ViewModel
|
|||
throw t.Exception;
|
||||
#else
|
||||
Log.Error($"Error happen in task dealing with viewupdate for results. {t.Exception}");
|
||||
_resultsViewUpdateTask =
|
||||
_resultsViewUpdateTask =
|
||||
Task.Run(updateAction).ContinueWith(continueAction, TaskContinuationOptions.OnlyOnFaulted);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -137,7 +141,8 @@ namespace Flow.Launcher.ViewModel
|
|||
if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(e.Results, pair.Metadata, e.Query, _updateToken)))
|
||||
{
|
||||
Log.Error("MainViewModel", "Unable to add item to Result Update Queue");
|
||||
};
|
||||
}
|
||||
;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -237,21 +242,24 @@ namespace Flow.Launcher.ViewModel
|
|||
|
||||
ReloadPluginDataCommand = new RelayCommand(_ =>
|
||||
{
|
||||
var msg = new Msg { Owner = Application.Current.MainWindow };
|
||||
var msg = new Msg
|
||||
{
|
||||
Owner = Application.Current.MainWindow
|
||||
};
|
||||
|
||||
MainWindowVisibility = Visibility.Collapsed;
|
||||
|
||||
PluginManager
|
||||
.ReloadData()
|
||||
.ContinueWith(_ =>
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
msg.Show(
|
||||
InternationalizationManager.Instance.GetTranslation("success"),
|
||||
InternationalizationManager.Instance.GetTranslation("completedSuccessfully"),
|
||||
"");
|
||||
}))
|
||||
.ConfigureAwait(false);
|
||||
.ReloadData()
|
||||
.ContinueWith(_ =>
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
msg.Show(
|
||||
InternationalizationManager.Instance.GetTranslation("success"),
|
||||
InternationalizationManager.Instance.GetTranslation("completedSuccessfully"),
|
||||
"");
|
||||
}))
|
||||
.ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -422,7 +430,10 @@ namespace Flow.Launcher.ViewModel
|
|||
Title = string.Format(title, h.Query),
|
||||
SubTitle = string.Format(time, h.ExecutedDateTime),
|
||||
IcoPath = "Images\\history.png",
|
||||
OriginQuery = new Query { RawQuery = h.Query },
|
||||
OriginQuery = new Query
|
||||
{
|
||||
RawQuery = h.Query
|
||||
},
|
||||
Action = _ =>
|
||||
{
|
||||
SelectedResults = Results;
|
||||
|
|
@ -448,7 +459,9 @@ namespace Flow.Launcher.ViewModel
|
|||
}
|
||||
}
|
||||
|
||||
private void QueryResults()
|
||||
private readonly IReadOnlyList<Result> _emptyResult = new List<Result>();
|
||||
|
||||
private async void QueryResults()
|
||||
{
|
||||
_updateSource?.Cancel();
|
||||
|
||||
|
|
@ -478,74 +491,73 @@ namespace Flow.Launcher.ViewModel
|
|||
|
||||
var plugins = PluginManager.ValidPluginsForQuery(query);
|
||||
|
||||
Task.Run(async () =>
|
||||
if (query.ActionKeyword == Plugin.Query.GlobalPluginWildcardSign)
|
||||
{
|
||||
// Wait 45 millisecond for query change in global query
|
||||
// if query changes, return so that it won't be calculated
|
||||
await Task.Delay(45, currentCancellationToken);
|
||||
if (currentCancellationToken.IsCancellationRequested)
|
||||
return;
|
||||
}
|
||||
|
||||
_ = Task.Delay(200, currentCancellationToken).ContinueWith(_ =>
|
||||
{
|
||||
// start the progress bar if query takes more than 200 ms and this is the current running query and it didn't finish yet
|
||||
if (!currentCancellationToken.IsCancellationRequested && _isQueryRunning)
|
||||
{
|
||||
if (query.ActionKeyword == Plugin.Query.GlobalPluginWildcardSign)
|
||||
{
|
||||
// Wait 45 millisecond for query change in global query
|
||||
// if query changes, return so that it won't be calculated
|
||||
await Task.Delay(45, currentCancellationToken);
|
||||
if (currentCancellationToken.IsCancellationRequested)
|
||||
return;
|
||||
}
|
||||
ProgressBarVisibility = Visibility.Visible;
|
||||
}
|
||||
}, currentCancellationToken, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default);
|
||||
|
||||
_ = Task.Delay(200, currentCancellationToken).ContinueWith(_ =>
|
||||
{
|
||||
// start the progress bar if query takes more than 200 ms and this is the current running query and it didn't finish yet
|
||||
if (!currentCancellationToken.IsCancellationRequested && _isQueryRunning)
|
||||
{
|
||||
ProgressBarVisibility = Visibility.Visible;
|
||||
}
|
||||
}, currentCancellationToken);
|
||||
// plugins is ICollection, meaning LINQ will get the Count and preallocate Array
|
||||
|
||||
// plugins is ICollection, meaning LINQ will get the Count and preallocate Array
|
||||
var tasks = plugins.Select(plugin => plugin.Metadata.Disabled switch
|
||||
{
|
||||
false => QueryTask(plugin),
|
||||
true => Task.CompletedTask
|
||||
}).ToArray();
|
||||
|
||||
Task[] tasks = plugins.Select(plugin => plugin.Metadata.Disabled switch
|
||||
{
|
||||
false => QueryTask(plugin),
|
||||
true => Task.CompletedTask
|
||||
}).ToArray();
|
||||
|
||||
try
|
||||
{
|
||||
// Check the code, WhenAll will translate all type of IEnumerable or Collection to Array, so make an array at first
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
try
|
||||
{
|
||||
// Check the code, WhenAll will translate all type of IEnumerable or Collection to Array, so make an array at first
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
if (currentCancellationToken.IsCancellationRequested)
|
||||
return;
|
||||
if (currentCancellationToken.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
// this should happen once after all queries are done so progress bar should continue
|
||||
// until the end of all querying
|
||||
_isQueryRunning = false;
|
||||
if (!currentCancellationToken.IsCancellationRequested)
|
||||
{
|
||||
// update to hidden if this is still the current query
|
||||
ProgressBarVisibility = Visibility.Hidden;
|
||||
}
|
||||
// this should happen once after all queries are done so progress bar should continue
|
||||
// until the end of all querying
|
||||
_isQueryRunning = false;
|
||||
if (!currentCancellationToken.IsCancellationRequested)
|
||||
{
|
||||
// update to hidden if this is still the current query
|
||||
ProgressBarVisibility = Visibility.Hidden;
|
||||
}
|
||||
|
||||
// Local function
|
||||
async Task QueryTask(PluginPair plugin)
|
||||
{
|
||||
// Since it is wrapped within a Task.Run, the synchronous context is null
|
||||
// Task.Yield will force it to run in ThreadPool
|
||||
await Task.Yield();
|
||||
// Local function
|
||||
async Task QueryTask(PluginPair plugin)
|
||||
{
|
||||
// Since it is wrapped within a Task.Run, the synchronous context is null
|
||||
// Task.Yield will force it to run in ThreadPool
|
||||
await Task.Yield();
|
||||
|
||||
var results = await PluginManager.QueryForPlugin(plugin, query, currentCancellationToken);
|
||||
if (currentCancellationToken.IsCancellationRequested || results == null) return;
|
||||
IReadOnlyList<Result> results = await PluginManager.QueryForPluginAsync(plugin, query, currentCancellationToken);
|
||||
|
||||
currentCancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(results, plugin.Metadata, query, currentCancellationToken)))
|
||||
{
|
||||
Log.Error("MainViewModel", "Unable to add item to Result Update Queue");
|
||||
};
|
||||
}
|
||||
}, currentCancellationToken)
|
||||
.ContinueWith(t => Log.Exception("|MainViewModel|Plugins Query Exceptions", t.Exception),
|
||||
TaskContinuationOptions.OnlyOnFaulted);
|
||||
results ??= _emptyResult;
|
||||
|
||||
if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(results, plugin.Metadata, query, currentCancellationToken)))
|
||||
{
|
||||
Log.Error("MainViewModel", "Unable to add item to Result Update Queue");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Flow.Launcher.ViewModel
|
|||
{
|
||||
public struct ResultsForUpdate
|
||||
{
|
||||
public List<Result> Results { get; }
|
||||
public IReadOnlyList<Result> Results { get; }
|
||||
|
||||
public PluginMetadata Metadata { get; }
|
||||
public string ID { get; }
|
||||
|
|
@ -16,7 +16,7 @@ namespace Flow.Launcher.ViewModel
|
|||
public Query Query { get; }
|
||||
public CancellationToken Token { get; }
|
||||
|
||||
public ResultsForUpdate(List<Result> results, PluginMetadata metadata, Query query, CancellationToken token)
|
||||
public ResultsForUpdate(IReadOnlyList<Result> results, PluginMetadata metadata, Query query, CancellationToken token)
|
||||
{
|
||||
Results = results;
|
||||
Metadata = metadata;
|
||||
|
|
|
|||
|
|
@ -17,20 +17,20 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
|
|||
// Reserved keywords in oleDB
|
||||
private const string reservedStringPattern = @"^[`\@\#\^,\&\/\\\$\%_]+$";
|
||||
|
||||
internal async static Task<List<Result>> ExecuteWindowsIndexSearchAsync(string indexQueryString, string connectionString, Query query, CancellationToken token)
|
||||
internal static async Task<List<Result>> ExecuteWindowsIndexSearchAsync(string indexQueryString, string connectionString, Query query, CancellationToken token)
|
||||
{
|
||||
var results = new List<Result>();
|
||||
var fileResults = new List<Result>();
|
||||
|
||||
try
|
||||
{
|
||||
using var conn = new OleDbConnection(connectionString);
|
||||
await using var conn = new OleDbConnection(connectionString);
|
||||
await conn.OpenAsync(token);
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
using var command = new OleDbCommand(indexQueryString, conn);
|
||||
await using var command = new OleDbCommand(indexQueryString, conn);
|
||||
// Results return as an OleDbDataReader.
|
||||
using var dataReaderResults = await command.ExecuteReaderAsync(token) as OleDbDataReader;
|
||||
await using var dataReaderResults = await command.ExecuteReaderAsync(token) as OleDbDataReader;
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
if (dataReaderResults.HasRows)
|
||||
|
|
@ -42,18 +42,18 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
|
|||
{
|
||||
// # is URI syntax for the fragment component, need to be encoded so LocalPath returns complete path
|
||||
var encodedFragmentPath = dataReaderResults
|
||||
.GetString(1)
|
||||
.Replace("#", "%23", StringComparison.OrdinalIgnoreCase);
|
||||
.GetString(1)
|
||||
.Replace("#", "%23", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var path = new Uri(encodedFragmentPath).LocalPath;
|
||||
|
||||
if (dataReaderResults.GetString(2) == "Directory")
|
||||
{
|
||||
results.Add(ResultManager.CreateFolderResult(
|
||||
dataReaderResults.GetString(0),
|
||||
path,
|
||||
path,
|
||||
query, 0, true, true));
|
||||
dataReaderResults.GetString(0),
|
||||
path,
|
||||
path,
|
||||
query, 0, true, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -63,6 +63,11 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
|
|||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// return empty result when cancelled
|
||||
return results;
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
// Internal error from ExecuteReader(): Connection closed.
|
||||
|
|
|
|||
Loading…
Reference in a new issue