崩溃后从同一位置启动线程

时间:2013-09-05 10:19:36

标签: c# multithreading azure workflow-foundation

我正在为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的任何提示?

所以,问题是,实施工作流程(本质上是一个工作流程)的最佳方法是什么,崩溃后可以从最后一点开始?

1 个答案:

答案 0 :(得分:2)

这正是Long-Running持久工作流程旨在解决的问题。

线程运行和暂停(可能是使用循环线程睡眠)并不像你说的那样理想。

可能是重新架构的时候了。你建议在每个步骤之后将当前的状态保持到数据库都可以正常工作,但如果你有带宽,我肯定会考虑长时间运行的工作流程。

http://msdn.microsoft.com/en-us/library/ff432975.aspx