从无法完成和处理的线程中恢复的最佳方法

时间:2013-10-28 20:12:46

标签: c# multithreading dotnet-httpclient

我有一个创建多个线程来发出HTTP请求的应用程序。我面临的问题是,如果请求失败,则线程将中止。我需要一些关于如何在新线程或现有线程中重新发出相同请求的想法。我正在使用BlockingCollection来添加和取消从HTTP请求中提取的项目。这并不重要,但它有助于理解我在做什么。请记住,HTTP请求可能会失败的原因有很多,所以我不打算发布请求的实际代码。我正在使用HTTPClient类来发出请求。

示例代码:

private void StartIntegration()
        {
            var queuCount = 0;

            var totalToSend = GetTotalToSendFromDb();

            for (int i = 0; i < 10; i++)
            {
                Task.Factory.StartNew(() =>
                {
                    while (queuCount != totalToSend)
                    {
                        //Get 500 items form the database to pass into the request                            
                        var items = GetRequestsFromDB(500);
                        if (items != null && items.Count > 0)
                        {
                            queuCount += items.Count;
                            SendRequest(mailing);
                        }


                    }
                });
            }


            for (int i = 0; i < 10; i++)
            {
                Task.Factory.StartNew(() => ConsumeResults());
            }

            while (_someGlobalVariable)
            {
                //Loop until the variable is false.

            }


        }

1 个答案:

答案 0 :(得分:0)

经过一番挖掘后,该请求存在一些问题,实际上又回来了。最初,我只是抓住了一个普通的例外。在更改它以捕获AggregateException之后,我能够找出请求错误的原因,反过来,我又能够再次调用该方法。我在方法中添加了一个变量,因此它只会在放弃之前重试X次。

另一个问题是我如何从数据库中获取数据。存储过程如下所示:

Create PROCEDURE [dbo].[GetTopListEmailItems](

@topCount   INT) 
AS 
  BEGIN 
      BEGIN 
          -- Identify the next N emails to be batched. UPDLOCK is to prevent another thread batching same emails
          SELECT TOP (@topCount) id 
          INTO   #tmpbatch 
          FROM  (SELECT  
                        Id, 
                        Md5Hash,
                                                EmailAddress,
                                                IsProcessed
                 FROM   ListEmailItems WITH (updlock,HOLDLOCK)) tmp 
          WHERE IsProcessed  = 0

          -- Stamp emails as sent. Assumed that PROC is called under a UOW. The batch IS the UOW 
          UPDATE e 
          SET    e.IsProcessed = 1 
          FROM   dbo.ListEmailItems e 
                 INNER JOIN #tmpbatch t 
                         ON e.id = t.id 

          -- Return the batch of emails to caller 
          SELECT e.* 
          FROM   dbo.ListEmailItems e 
                 INNER JOIN #tmpbatch t 
                         ON e.id = t.id 
      END 
  END  

此过程应该只获取Top X记录并阻止线程,因此不会多次拉出相同的记录。问题出在C#代码上。在事务中包装数据库调用之后,它不再多次拉出相同的记录。

private List<ListEmailItem> GetRequests(int topCount,bool reset = false)
        {
            List<ListEmailItem> items;
            using (var tran = new TransactionScope(
                // a new transaction will always be created
                TransactionScopeOption.RequiresNew,
                // we will allow volatile data to be read during transaction
                new TransactionOptions()
                {
                    IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted
                }
                ))
            {
                using (var context = new IntegrationContext())
                {
                    items = context.Database.SqlQuery<ListEmailItem>("Exec GetTopListEmailItems @topCount",
                        new SqlParameter("topCount", topCount)).Select(s => new ListEmailItem()
                        {
                            Id = s.Id,
                            Md5Hash = s.Md5Hash,
                            EmailAddress = s.EmailAddress,

                        }).ToList();


                }

                tran.Complete();
            }

            return items;
        }