C# 在.NET中调用分布式系统的批处理建议
我希望得到一些关于我们团队中几乎每一个项目都会出现的问题的提示 在这些项目中,主要目标通常是对大量“项目”执行某种处理。 “处理”基本上是一系列操作,每个操作都可能因各种原因而失败 也许我可以通过描述一个示例应用程序来最好地解释它 将以下内容想象为我们的一个应用程序的简化版本:(实际上可能是1000 LoC左右) 虽然这些是有问题的要求:C# 在.NET中调用分布式系统的批处理建议,c#,.net,batch-processing,distributed-computing,C#,.net,Batch Processing,Distributed Computing,我希望得到一些关于我们团队中几乎每一个项目都会出现的问题的提示 在这些项目中,主要目标通常是对大量“项目”执行某种处理。 “处理”基本上是一系列操作,每个操作都可能因各种原因而失败 也许我可以通过描述一个示例应用程序来最好地解释它 将以下内容想象为我们的一个应用程序的简化版本:(实际上可能是1000 LoC左右) 虽然这些是有问题的要求: 每天都有数千个文件需要处理 要处理文件,我们需要混合执行数据库操作和对外部系统的调用(不可能进行事务处理) SendMail()可能由于各种原因而失败,例如
- 每天都有数千个文件需要处理
- 要处理文件,我们需要混合执行数据库操作和对外部系统的调用(不可能进行事务处理)
- SendMail()可能由于各种原因而失败,例如:。
- 与邮件服务器的连接失败(稍后应自动重试,而不会阻止处理其他文件)
- 地址拼写错误(可能必须手动更正,然后重试)
- 其他意想不到的原因,没有人会预料到,只有在应用程序正常运行后才能弄清楚
- 正确发送的邮件可能会“反弹”——可能在发送几天后。我们需要在收到反弹通知后打印出文件
- 文件的实际打印可能会失败,而应用程序无法通知。(即打印机故障)
- 我们的老板可能会问以下问题:
- 上周发送或打印了哪些文件
- ABC文件本来应该打印出来的,但现在不见了。应用程序是否尝试打印它?如果是,什么时候
- 文件XYZ发生了什么,我们尝试发送和打印它的频率和时间
- 哪些项目处理正确
- 处理项目时发生了哪些错误
- 在某些情况下,将失败的项目再次标记为“未处理”是可行的,因此它只是再次被处理
- 但在其他情况下,我们不能从一开始就重新处理该项,因为以前失败的尝试可能已经造成了无法回滚的副作用。(在先前失败的步骤中恢复处理的方法可能是好的)
- 我们希望跟踪“修复尝试”以及有人试图修复某个项目后发生的情况
- 所有处理都是在windows服务的C#循环中完成的
- 要处理的项由数据库表中的行表示(称为“触发器”-行)
- 在处理之后,触发器行被标记为一个状态标志,其含义如下:“完成”、“打印时出错”、“未知错误”等
- 一些用于最后故障排除(NLog)的平面文件日志记录
- 使用触发器表上的SQL获取有关已处理项的信息
- 将触发器状态设置为“未处理”以重复出现错误的项
- “BatchFlow”框架(也在NuGet上)
- 我想这可能有助于保持代码的整洁,但会给我们留下所有其他问题,比如日志记录和异步错误恢复
- 消息传递框架,如MassTransit或EasyNetQ。
我可以看到消息传递如何帮助解决我们的一些问题,比如以后可以重试工作流的单个步骤,但是:
- 无论采用何种框架,似乎都没有一种简单的方法来检查和重试错误消息。 看起来每个消息传递框架基本上只是将错误消息抛出到一个错误队列,就这样。 但是为了检查和重试这些错误,您似乎总是必须实现相当多的附加逻辑。 一个想法是使用所有错误消息并将它们放入数据库中,但我认为 为什么这样的东西还没有成为框架的一部分。。。其他人究竟是如何处理他们的错误的
- 我希望,通过消息传递,可以很容易地保存与所处理的消息相关的历史日志 业务事务,但这似乎也是您必须完全在消息传递之上实现的 框架(或者可能我试图用错误的方法解决问题。)
希望这篇文章不会太混乱,但我很乐意在需要的地方详细说明。首先,这是一个需要立即解决的大问题 这是一个企业级的问题,最好在更高的抽象级别上解决。在SOA术语中,您必须将系统分解为只做它需要做的事情的较小应用程序。坚定地思考[1]。思考单一责任
foreach (var pdfFile in unprocessedPdfFiles)
{
var mailWasSent = SendMail(pdfFile);
if(!mailWasSent)
{
PrintFile(pdfFile);
}
MarkAsProcessed(pdfFile);
}