我有一个创建多个线程来发出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.
}
}
答案 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;
}