Аццкий ад и асинхронная асинхронность
От: Artem Korneev США https://www.linkedin.com/in/artemkorneev/
Дата: 12.11.16 05:33
Оценка:
Написал я тут в коде одну конструкцию, которая пугает меня своей сложностью.
Это — кусок кода класса RestServiceClient, предназначенного для отправки запросов HTTP-серверам. Эта функция создаёт HttpClient и вызывает коллбэк, указанный в качестве параметра.

public async Task InvokeHttpCall(Func<HttpClient, Task<HttpResponseMessage>> callback)
{
    using (var httpClient = new HttpClient())
    {
        HttpResponseMessage response = null;
        var http = httpClient;

        await this.retryPolicy.ExecuteAndCaptureAsync(
            async () =>
                await Task.Run(
                    async () => response = await callback.Invoke(http)));
    }
}


Сделано это для того чтоб не повторять один и тот же код для обёртки каждого типа HTTP-запроса. Здесь я привожу упрощённый код, реально там ещё установка разных заголовков аутентификации, замеры времени обработки запроса и т.д. Результат выполнения запроса (переменная response) используется потом для возврата HttpStatusCode. Там несколько похожих методов, с десериализацией результата и без него, я привожу здесь простейший вариант. Используется этот метод так:

public async Task DeleteAsync(Uri uri)
{
    await this.httpCallsInvoker.InvokeHttpCall((httpClient) => httpClient.DeleteAsync(uri));
}


Здесь идёт обёртка для DELETE-запоса, остальные типы запросов реализованы аналогично, но с дополнительными параметрами.

Вот эта строчка:

        await this.retryPolicy.ExecuteAndCaptureAsync


Использует библиотеку Polly для применения разных политик обработки ошибок соединения (retry, circuit breaker, и т.д.). Оно тоже всё асинхронное и принимает коллбэки в качестве параметров.

Так вот.. это всё работает, но результат мне самому кажется излишне сложным. Особенно меня смущает вот эта лестница из async/await:

        await this.retryPolicy.ExecuteAndCaptureAsync(
            async () =>
                await Task.Run(
                    async () => response = await callback.Invoke(http)));


Хочется всё это переписать к более понятному виду, потому как сейчас, кроме меня, этот код врятли кто-нибудь разберёт в моей команде. Коллеги, подскажите, как и с какой стороны к этому лучше подходить? Нет ли тут каких-то явных косяков, которые я не замечаю? Мне кажется, что что-то в этой последовательности async/await можно упростить, но я пока не смог.
С уважением, Artem Korneev.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.