我正在为Windows Azure编写一个辅助角色。工作程序从队列接收消息,并为每个消息传递一个线程。
线程正在调用外部API并且涉及大量线程等待:即我可以调用“创建实例”,API将返回202 Accepted
,然后我将不得不轮询API以获得“已完成”答案。有时等待可能是5分钟。整个过程可能需要10到30分钟,大约有10次调用API。
Azure Worker Role的生命周期中的30分钟很多,并且在此期间可能会发生重新启动/重新部署/崩溃。而且我的进程不是幂等的,我无法在没有问题的情况下两次创建相同的资源。
我想做的是每次对API的关键调用,都将线程的状态存储在某个地方。因此,如果线程在某处崩溃,另一个工作者角色可以从队列中获取一条消息,并从之前被中断的同一进程点起飞。
其中一个想法是报告线程状态并在某处继续存在。像这样的伪代码:
pubilc class WorkerRole{
public override Run(){
while(true)
{
var message = Queue.GetMessage();
var messageProcessor = new MessageProcessor(message);
var thread = new Thread();
thread.Run(messageProcessor.Process());
Thread.Sleep(1 minute);
}
}
}
public class MessageProcessor
{
private QueueMessage message;
public MessageProcessor(QueueMessage message){
this.message = message
}
public void Process()
{
if(!ThreadReporter.IsComplete(message, "Step1")
{
ExtenalApi.StartStep1();
}
ThreadReporter.ReportCompletion(message, "Step1");
if(!ThreadReporter.IsComplete(message, "Step2"))
{
ExternalApi.StartStep2();
}
ThreadReporter.ReportCompletion(message, "Step2");
}
}
ThreadReporter
会在DB中的某处保存一个标志,表示Step1已完成,或者是否已为该特定消息(工作请求)设置了Step1的标志。
我可以感觉到这种方法会有很多问题而代码会很糟糕。但我很难想出一个更好的方法来做到这一点。
我见过Jon Skeet正在保存应用程序的某种MemoryDump,并在重新启动后从同一个地方起飞。线程状态是否可以序列化以保存在DB中?
我也听说Workflow Foundation也可以这样做。我从来没有和WF合作过,也没有任何关于它的线索。关于WF的任何提示?
所以,问题是,实施工作流程(本质上是一个工作流程)的最佳方法是什么,崩溃后可以从最后一点开始?
答案 0 :(得分:2)
这正是Long-Running持久工作流程旨在解决的问题。
线程运行和暂停(可能是使用循环线程睡眠)并不像你说的那样理想。
可能是重新架构的时候了。你建议在每个步骤之后将当前的状态保持到数据库都可以正常工作,但如果你有带宽,我肯定会考虑长时间运行的工作流程。