我很难让我的任务保持持久并从 WCF 服务无限期运行。我可能这样做的方式错误,并愿意接受建议。
我有一个任务,它开始处理放入 BlockingCollection 的任何传入请求。据我了解,GetConsumingEnumerable() 方法应该允许我在数据到达时持久地提取数据。它本身没有问题。我能够处理数十个请求,而不会出现一个错误或缺陷,使用 Windows 表单填写请求并提交它们。一旦我对这个过程充满信心,我就通过asmx Web服务将其连接到我的站点,并使用jQuery ajax调用来提交请求。
网站根据提交的 URL 提交请求,Web 服务从该 URL 下载 html 内容,并在内容中查找其他 URL。然后,它继续为找到的每个 url 创建一个请求,并将其提交给 BlockingCollection。在 WCF 服务中,如果应用程序处于联机状态(即任务已启动),它将通过 Parallel.ForEach 使用 GetConsumingEnumerable 拉取请求并处理请求。
这适用于前几个提交,但随后任务会意外停止。当然,这比我在测试中模拟的请求多 10 倍 - 但我希望它只是节流。我相信问题出在我启动任务的方法中:
public void Start()
{
Online = true;
Task.Factory.StartNew(() =>
{
tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
ParallelOptions options = new ParallelOptions();
options.MaxDegreeOfParallelism = 20;
options.CancellationToken = token;
try
{
Parallel.ForEach(FixedWidthQueue.GetConsumingEnumerable(token), options, (request) =>
{
Process(request);
options.CancellationToken.ThrowIfCancellationRequested();
});
}
catch (OperationCanceledException e)
{
Console.WriteLine(e.Message);
return;
}
}, TaskCreationOptions.LongRunning);
}
我曾考虑过将其移动到 WF4 服务中,只需将其连接到工作流中并使用工作流持久性,但除非必要,否则我不愿意学习 WF4。如果需要更多信息,请告诉我。
您显示的代码本身是正确的。
但是,有一些事情可能会出错:
- 如果发生异常,您的任务将停止(当然)。尝试添加 try-catch 并记录异常。
- 如果在托管环境(ASP.NET、WCF、SQL Server)中启动工作线程,则主机可以任意(无理由)决定关闭任何工作进程。例如,如果您的 ASP.NET 网站在一段时间内处于非活动状态,则应用将关闭。我刚才提到的主机不是为了运行自定义线程。也许,使用专用应用程序(.exe)甚至Windows服务会取得更大的成功。
事实证明,此问题的原因是 WCF 绑定配置。任务突然停止,因为 WCF 由于打开超时而终止了连接。打开超时设置是请求在超时之前等待服务打开连接的时间。在某些情况下,它达到了 10 个最大连接的限制,并导致传入连接在等待连接时备份。我确保在事务完成后关闭了与主机的所有连接 - 所以我放弃了提高最大连接数和打开超时期限。在此之后 - 它完美运行。