mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 10:58:30 -05:00
File Browser: Adding async task exception handling (#504)
* Replacing Dictionary with ConcurrentDictionary since values are accessed in async contexts * Adding new method to allow async tasks to be executed in the exception continuation * Adding unit tests for the aforementioned * Adding exception handling to async tasks in file browser service * Updating query execution async handling to use the async version * Removing unnecesary send result from continuewithonfaulted
This commit is contained in:
@@ -18,33 +18,83 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||
/// <remarks>
|
||||
/// This will effectively swallow exceptions in the task chain.
|
||||
/// </remarks>
|
||||
/// <param name="task">The task to continue</param>
|
||||
/// <param name="antecedent">The task to continue</param>
|
||||
/// <param name="continuationAction">
|
||||
/// An optional operation to perform after exception handling has occurred
|
||||
/// </param>
|
||||
/// <returns>Task with exception handling on continuation</returns>
|
||||
public static Task ContinueWithOnFaulted(this Task task, Action<Task> continuationAction)
|
||||
public static Task ContinueWithOnFaulted(this Task antecedent, Action<Task> continuationAction)
|
||||
{
|
||||
return task.ContinueWith(t =>
|
||||
return antecedent.ContinueWith(task =>
|
||||
{
|
||||
// If the task hasn't faulted or has an exception, skip processing
|
||||
if (!t.IsFaulted || t.Exception == null)
|
||||
if (!task.IsFaulted || task.Exception == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Construct an error message for an aggregate exception and log it
|
||||
StringBuilder sb = new StringBuilder("Unhandled exception(s) in async task:");
|
||||
foreach (Exception e in task.Exception.InnerExceptions)
|
||||
{
|
||||
sb.AppendLine($"{e.GetType().Name}: {e.Message}");
|
||||
sb.AppendLine(e.StackTrace);
|
||||
}
|
||||
Logger.Write(LogLevel.Error, sb.ToString());
|
||||
LogTaskExceptions(task.Exception);
|
||||
|
||||
// Run the continuation task that was provided
|
||||
continuationAction?.Invoke(t);
|
||||
try
|
||||
{
|
||||
continuationAction?.Invoke(task);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Write(LogLevel.Error, $"Exception in exception handling continuation: {e}");
|
||||
Logger.Write(LogLevel.Error, e.StackTrace);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds handling to check the Exception field of a task and log it if the task faulted.
|
||||
/// This version allows for async code to be ran in the continuation function.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will effectively swallow exceptions in the task chain.
|
||||
/// </remarks>
|
||||
/// <param name="antecedent">The task to continue</param>
|
||||
/// <param name="continuationFunc">
|
||||
/// An optional operation to perform after exception handling has occurred
|
||||
/// </param>
|
||||
/// <returns>Task with exception handling on continuation</returns>
|
||||
public static Task ContinueWithOnFaulted(this Task antecedent, Func<Task, Task> continuationFunc)
|
||||
{
|
||||
return antecedent.ContinueWith(task =>
|
||||
{
|
||||
// If the task hasn't faulted or doesn't have an exception, skip processing
|
||||
if (!task.IsFaulted || task.Exception == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LogTaskExceptions(task.Exception);
|
||||
|
||||
// Run the continuation task that was provided
|
||||
try
|
||||
{
|
||||
continuationFunc?.Invoke(antecedent).Wait();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Write(LogLevel.Error, $"Exception in exception handling continuation: {e}");
|
||||
Logger.Write(LogLevel.Error, e.StackTrace);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void LogTaskExceptions(AggregateException exception)
|
||||
{
|
||||
// Construct an error message for an aggregate exception and log it
|
||||
StringBuilder sb = new StringBuilder("Unhandled exception(s) in async task:");
|
||||
foreach (Exception e in exception.InnerExceptions)
|
||||
{
|
||||
sb.AppendLine($"{e.GetType().Name}: {e.Message}");
|
||||
sb.AppendLine(e.StackTrace);
|
||||
}
|
||||
Logger.Write(LogLevel.Error, sb.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user