mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-22 09:35:38 -05:00
* Multi-thread server lookup to increase perf for multiple subscriptions * Use parallel execution for listsubscriptions - Also refactored parallel execution code to be a bit more generic
119 lines
4.8 KiB
C#
119 lines
4.8 KiB
C#
//
|
|
// Copyright (c) Microsoft. All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Microsoft.SqlTools.ResourceProvider.Core
|
|
{
|
|
/// <summary>
|
|
/// Utils class supporting parallel querying of Azure resources
|
|
/// </summary>
|
|
public static class AzureUtil
|
|
{
|
|
/// <summary>
|
|
/// Execute an async action for each input in the a list of input in parallel.
|
|
/// If any task fails, adds the exeption message to the response errors
|
|
/// If cancellation token is set to cancel, returns empty response.
|
|
/// Note: Will not throw if errors occur. Instead the caller should check for errors and either notify
|
|
/// or rethrow as needed.
|
|
/// </summary>
|
|
/// <param name="session">Resource management session to use to call the resource manager</param>
|
|
/// <param name="inputs">List of inputs</param>
|
|
/// <param name="lookupKey">optional lookup key to filter the result</param>
|
|
/// <param name="cancellationToken">Cancellation token</param>
|
|
/// <param name="asyncAction">Async action</param>
|
|
/// <returns>ServiceResponse including the list of data and errors</returns>
|
|
public static async Task<ServiceResponse<TResult>> ExecuteGetAzureResourceAsParallel<TConfig, TInput, TResult>(
|
|
TConfig config,
|
|
IEnumerable<TInput> inputs,
|
|
string lookupKey,
|
|
CancellationToken cancellationToken,
|
|
Func<TConfig,
|
|
TInput,
|
|
string,
|
|
CancellationToken,
|
|
CancellationToken,
|
|
Task<ServiceResponse<TResult>>> asyncAction
|
|
)
|
|
{
|
|
List<TResult> mergedResult = new List<TResult>();
|
|
List<Exception> mergedErrors = new List<Exception>();
|
|
try
|
|
{
|
|
if (inputs == null)
|
|
{
|
|
return new ServiceResponse<TResult>(mergedResult);
|
|
}
|
|
List<TInput> inputList = inputs.ToList();
|
|
|
|
ServiceResponse<TResult>[] resultList = new ServiceResponse<TResult>[inputList.Count];
|
|
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
|
|
var tasks = Enumerable.Range(0, inputList.Count())
|
|
.Select(async i =>
|
|
{
|
|
ServiceResponse<TResult> result = await GetResult(config, inputList[i], lookupKey, cancellationToken,
|
|
cancellationTokenSource.Token, asyncAction);
|
|
//server name is used to filter the result and if the data is already found not, we need to cancel the other tasks
|
|
if (!string.IsNullOrEmpty(lookupKey) && result.Found)
|
|
{
|
|
cancellationTokenSource.Cancel();
|
|
}
|
|
resultList[i] = result;
|
|
return result;
|
|
}
|
|
);
|
|
|
|
await Task.WhenAll(tasks);
|
|
|
|
if (!cancellationToken.IsCancellationRequested)
|
|
{
|
|
foreach (ServiceResponse<TResult> resultForEachInput in resultList)
|
|
{
|
|
mergedResult.AddRange(resultForEachInput.Data);
|
|
mergedErrors.AddRange(resultForEachInput.Errors);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
mergedErrors.Add(ex);
|
|
return new ServiceResponse<TResult>(mergedResult, mergedErrors);
|
|
}
|
|
return new ServiceResponse<TResult>(mergedResult, mergedErrors);
|
|
}
|
|
|
|
private static async Task<ServiceResponse<TResult>> GetResult<TConfig, TInput, TResult>(
|
|
TConfig config,
|
|
TInput input,
|
|
string lookupKey,
|
|
CancellationToken cancellationToken,
|
|
CancellationToken internalCancellationToken,
|
|
Func<TConfig,
|
|
TInput,
|
|
string,
|
|
CancellationToken,
|
|
CancellationToken,
|
|
Task<ServiceResponse<TResult>>> asyncAction
|
|
)
|
|
{
|
|
if (cancellationToken.IsCancellationRequested || internalCancellationToken.IsCancellationRequested)
|
|
{
|
|
return new ServiceResponse<TResult>();
|
|
}
|
|
try
|
|
{
|
|
return await asyncAction(config, input, lookupKey, cancellationToken, internalCancellationToken);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return new ServiceResponse<TResult>(ex);
|
|
}
|
|
}
|
|
}
|
|
}
|