我正在开发一个与Web服务通信的应用程序。客户端应用程序(silverlight-4.0)将调用Web服务并触发长时间运行的任务。因为任务完成需要一些时间,所以它在一个单独的线程中执行。 (使用System.Threading.Tasks.Task.Factory.StartNew()创建单独的任务。)启动任务后,服务调用将返回一个ID并完成连接。
这个ID应该是我需要识别任务的东西,所以我可以与它进行通信。
可能使用其他连接进行下一次调用,以检查任务是否已完成。为此,ID是呼叫的一部分。在服务器上,它现在需要检查任务是否仍在运行或是否已完成。如何再次找到此任务?
该服务在Azure上运行,并且由于负载平衡,第二次调用可能位于完全不同的系统上。在我看来,这不可能做到,但再次...... 此Q与this Q。
相关答案 0 :(得分:4)
让任务在表存储/ appfabric缓存中报告其状态。然后当nsomeone轮询状态时,只需从使用的持久性机制中读取任务ID X的相应状态。
答案 1 :(得分:3)
这样做的正确方法是使用基于队列的通信。原因是可伸缩性。您希望服务的“实例”获取请求,并且您希望“实例”将结果返回给客户端吗?
您可以快速查看我的一篇关于AppFabric Queues的博客文章,但它们过于笨重。这就是我的意思:
创建一个WorkerRequest类,看起来像这样
public class WorkerRequest {
string clientId;
MyTaskEnum taskToPerform;
}
写入队列存储,(在我的生产代码中,我使用的是一个我还没有写过博客的包装器,但计划:)),添加请求。
让工作线程监听此队列,并在收到请求时,生成一个新线程来完成它。完成后,使用您的任务&写入表存储。客户端ID作为您的密钥。这样你就可以随时检查状态(一个简单的/ GET /请求到表)+你有解耦和&可扩展性已经解决了。
希望它有所帮助。
UPDATE:想要解释一下,所以我决定更新帖子=)
您可以在“Web角色”中创建WCF Web服务,这就是我要做的。我前一段时间blogged about。在同一个角色中,您可以创建工作人员。你通过一个实现RoleEntryPoint
的类来做到这一点。此类(位于Microsoft.WindowsAzure.ServiceRuntime中)如下所示:
public abstract class RoleEntryPoint
{
public virtual bool OnStart()
{
return true;
}
public virtual void Run()
{
Thread.Sleep(-1);
}
public virtual void OnStop()
{
}
}
您只需在Run中实现while(true)循环,该循环会询问Queue是否有任何新消息需要处理。收到此类消息后不会生成新消息,只需处理即可。如果要缩放它,可以通过添加新实例进行缩放。显然,这可能是昂贵的,所以实际上产生新线程是明智的,但仅限于某个限制,例如,最多5个线程。如果池中没有线程,则将消息返回到队列(完成消息后需要调用Complete()
,否则不一定会被删除)。它会在以后或其他工作人员接收。
因此,当工作线程完成时,将结果写入表存储,然后就完成了。
答案 2 :(得分:2)
任务只需要在某个地方保持已完成,并在预期结果时存储结果。
您可以将任务ID存储在表存储或SQL Azure中,无论您身在何处。后续轮询以查看是否已完成,只需检查此存储并返回是否已完成。
解决此问题的另一种方法是让长时间运行的任务以辅助角色运行。如果此工作者角色公开了内部端点,那么任何Web角色都可以询问工作者角色是否已完成。