1

我正在为 Windows Azure 编写一个 Worker Role。工作人员从队列中接收消息,并为每条消息启动一个线程。线程正在调用外部 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 并在重新启动后从同一个地方起飞。线程状态可以序列化以保存在数据库中吗?

我也听说 Workflow Foundation 也可以做到这一点。我从未与WF合作过,对此一无所知。关于WF的任何提示?

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

4

1 回答 1

2

这正是长期运行的持久化工作流旨在解决的问题。

正如您所说,让线程运行和暂停(可能是循环线程睡眠)并不理想。

可能是时候进行一些重新架构了。您建议在每个步骤后将当前播放状态保留到数据库会很好,但如果您有带宽,我肯定会研究长期运行的工作流程。

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

于 2013-09-05T11:45:31.787 回答