C #: el hilo se aborta sin completar las solicitudes restantes
Implementé un programador que envía solicitudes a un punto final de terceros. Después de recibir la respuesta, mi base de datos local se actualiza con la respuesta. Actualmente, estoy enviando más de 50 mil solicitudes (1 mil solicitudes cada 10 minutos) y proceso la respuesta. A veces, el problema es que el servidor de terceros no responde o se agota el tiempo de espera de la solicitud. En este caso, obtengo una excepción y el hilo se cancela sin procesar las solicitudes restantes. Lo que necesito es no abortar el hilo y continuar con el siguiente registro para que el registro perdido se procese en otro lote. Aquí está el código que estoy usando.
public class ScheduledAPIJob : IJob
{
public Task Execute(IJobExecutionContext context)
{
Task taskAPI = Task.Factory.StartNew(() => ProcessAPI());
return taskAPI;
}
void ProcessAPI()
{
//Error logging object
SchedulerLogWriter lw = new SchedulerLogWriter("Logs\\Scheduler");
List<WeatherData> list = new List<WeatherData>();
APIQueueBAL objBal = new APIQueueBAL();
//List of endpoints to hit.
var APIQueue = objBal.QueuedAPIs();
foreach (var item in APIQueue)
{
try
{
var endpoint = item.FunctionParameters;
HttpRequestHelper objRequestHelper = new HttpRequestHelper();
//Response from API
var response = objRequestHelper.GetAPIResponse(endpoint);
////Update local database.
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
list = JsonConvert.DeserializeObject<List<WeatherData>>(response.Content.ReadAsStringAsync().Result);
objBal.ProcessWeatherData(item, list);
}
}
catch (Exception ex)
{
lw.WriteLog(ex.Message);
lw.WriteLog(Convert.ToString(ex.InnerException));
lw.WriteLog(ex.StackTrace);
}
}
}
}
public class HttpRequestHelper
{
public HttpResponseMessage GetAPIResponse(string apiEndpoint)
{
using (var client = new HttpClient())
{
var getTask = client.GetAsync(apiEndpoint);
getTask.Wait();
return getTask.Result;
}
}
}
Respuestas
Según HttpClientdocumentación:
HttpClient
está diseñado para instanciarse una vez por aplicación, en lugar de por uso.
HttpClient
instancia por solicitud puede causar un Agotamiento de Socket que hace que no sea posible enviar nuevas solicitudes.
a veces el servidor de terceros no responde
Tal vez el servidor de terceros esté bien, pero sus Sockets no. También puede hacer que ThreadAbortException
se envíe una nueva solicitud, especialmente si está ejecutando la solicitud sincrónicamente. getTask.Wait()
es una llamada de sincronización sobre asincrónica que no se recomienda ni es necesaria aquí.
Considere este código actualizado para usar async/await
.
public class ScheduledAPIJob : IJob
{
public Task Execute(IJobExecutionContext context)
{
return ProcessAPI();
}
private async Task ProcessAPI()
{
//Error logging object
SchedulerLogWriter lw = new SchedulerLogWriter("Logs\\Scheduler");
APIQueueBAL objBal = new APIQueueBAL();
//List of endpoints to hit.
var APIQueue = objBal.QueuedAPIs();
foreach (var item in APIQueue)
{
try
{
string endpoint = item.FunctionParameters;
//Response from API
List<WeatherData> list = await HttpRequestHelper.GetAPIResponseAsync<List<WeatherData>>(endpoint);
objBal.ProcessWeatherData(item, list);
}
catch (Exception ex)
{
lw.WriteLog(ex.Message);
lw.WriteLog(Convert.ToString(ex.InnerException));
lw.WriteLog(ex.StackTrace);
}
}
}
}
public static class HttpRequestHelper
{
private static readonly HttpClient client = new HttpClient();
public static async Task<T> GetAPIResponseAsync<T>(string apiEndpoint)
{
using (HttpResponseMessage response = await client.GetAsync(apiEndpoint, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
{
response.EnsureSuccessStatusCode(); // throws if not success
string json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return JsonConvert.DeserializeObject<T>(json);
}
}
}
Nota: si está usando .Result
o .GetAwaiter().GetResult()
no completado Task
, significa que algo salió mal y hay una mala práctica frente a usted que posiblemente cause un punto muerto.
El código anterior se puede mejorar para solicitudes simultáneas, por ejemplo, enviar todas a la vez o manejar con el límite máximo activo a la vez. Pero primero es mejor asegurarse de que el código anterior funcione.