C #: İş parçacığı kalan istekleri tamamlamadan iptal edilir

Aug 18 2020

Üçüncü taraf bir uç noktaya istek gönderen bir planlayıcı uyguladım. Yanıtı aldıktan sonra yerel veritabanım yanıtla güncellenir. Şu anda 50.000'den fazla istek gönderiyorum (her 10 dakikada 1K istek) ve yanıtı işliyorum. Sorun bazen üçüncü taraf sunucunun yanıt vermemesi veya isteğin zaman aşımına uğramasıdır. Bu durumda bir istisna alırım ve kalan istekleri işleme koymadan iş parçacığı iptal edilir. İhtiyacım olan şey, iş parçacığını iptal edip bir sonraki kayda geçmemek, böylece kaçırılan kaydın başka bir partide işlenmesi. İşte kullandığım kod.

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;
        }
    }
}

Yanıtlar

aepot Aug 18 2020 at 14:38

Gereğince HttpClientbelgeler:

HttpClient kullanım başına değil, uygulama başına bir kez somutlaştırılması amaçlanmıştır.

HttpClientistek başına örnek, yeni isteklerin gönderilmesini mümkün kılan Soket Tükenmesine neden olabilir .

bazen üçüncü taraf sunucu yanıt vermiyor

Belki üçüncü taraf sunucuda sorun yok ama Soketleriniz değil. Ayrıca, ThreadAbortExceptionözellikle isteği eşzamanlı olarak çalıştırıyorsanız, bazı yeni isteklerin gönderilmesine de neden olabilir . getTask.Wait()Eşitleme üzerinden eşzamanlı çağrıdır, burada önerilmez ve gerekli değildir.

Bu güncellenmiş kodu kullanmayı düşünün 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);
        }
    }
}

Not: kullanıyorsanız .Resultveya .GetAwaiter().GetResult()tamamlanmadıysa Task, bir şeylerin ters gittiği ve önünüzde muhtemelen bir kilitlenmeye neden olan kötü bir uygulama olduğu anlamına gelir.

Yukarıdaki kod, eşzamanlı istekler için geliştirilebilir, örneğin hepsini bir kerede gönder veya bir kerede maksimum aktif sınırla işleme. Ancak öncelikle yukarıdaki kodun çalıştığından emin olmak daha iyidir.