En mi aplicación, estoy usando la biblioteca Polly para llamar a una API.
La API puede devolver advertencias y errores en la respuesta. Para algunas de estas advertencias quiero volver a intentarlo 2 veces y la próxima vez me gustaría devolver la respuesta a la persona que llama .
Se puede hacer esto?
@StephenCleary señaló que solo debería manejar la respuesta y no lanzar una excepción.
Para verificar la respuesta necesito esperar el Contenido. Lo siguiente no se compilará, ¿alguien puede ver cómo puedo hacer esto?
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() { return HttpPolicyExtensions .HandleTransientHttpError() .OrResult(async msg => { var content = await msg.Content.ReadAsStringAsync(); return content.Contains("errorcode123"); }) .WaitAndRetryAsync(2, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); }Hay un par de partes en esto.
Primero, no desea lanzar una excepción si el resultado tiene advertencias. En ese momento, tal vez quiera volver a intentarlo y tal vez no; el código no se puede decir todavía. Pero lanzar una excepción significa que la respuesta se descarta, por lo que lanzar en este punto no es correcto.
En su lugar, ese controlador debe marcar la respuesta con un indicador de "tiene advertencias". Esto es posible usando HttpRequestMessage.Properties ( HttpRequestMessage.Options en .NET 5). Algo como esto:
private static readonly string IsInternalServerResponseKey = Guid.NewGuid().ToString("N"); ... var httpResponse = ... var responseContent = ... if (InternalServerResponse(responseContent)) { httpResponse.RequestMessage.Properties[IsInternalServerResponseKey] = true; }De esta manera, hay un indicador adjunto a la solicitud/respuesta que otras partes del código pueden leer, específicamente el controlador de reintento de Polly.
La otra parte de la solución es el conteo de reintentos. Normalmente, Polly tiene delegados que determinan si debe reintentar o no, y esos delegados son autónomos: excepciones de reintento de este tipo o respuestas de reintento similares. En este caso, desea volver a intentar una respuesta que coincida con una determinada forma, pero solo si no ha habido demasiados reintentos, y si ha habido demasiados reintentos y la respuesta coincide con una forma de "reintento", entonces no desea para lanzar una excepción pero devolver la respuesta en su lugar.
Esto es inusual, pero factible. Deberá capturar las "consideraciones externas" (en este caso, el recuento de reintentos) dentro del contexto de Polly. Luego, su delegado de reintentos puede extraer el recuento de reintentos del contexto y basar su decisión en eso. Algo como esto debería funcionar:
private static readonly string RetryCountKey = Guid.NewGuid().ToString("N"); static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() { return HttpPolicyExtensions .HandleTransientHttpError() .OrResult(response => { return IsInternalServerResponse() && RetryCount() <= 2; bool IsInternalServerResponse() { if (!response.RequestMessage.Properties.TryGetValue(IsInternalServerResponseKey, out var objValue) || objValue is not bool boolValue) return false; return boolValue; } int RetryCount() { if (!response.RequestMessage.GetPolicyExecutionContext().TryGetValue(RetryCountKey, out var objValue) || objValue is not int intValue) return 0; return intValue; } }) .WaitAndRetryAsync(2, (retryAttempt, _) => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (_, _, retryAttempt, context) => context[RetryCountKey] = retryAttempt); } No he probado esto; es posible que haya un error de uno entre los 2 pasados a WaitAndRetryAsync y los 2 usados para comparar el retryCount .