通过Web应用程序处理作业:实时状态更新和后端消息传递

时间:2012-10-04 18:57:52

标签: python web-applications websocket messaging zeromq

我想实现一个(开源)Web应用程序,用户通过他的浏览器向Python Web应用程序发送某种请求。请求数据用于定义和提交某种繁重的计算工作。计算工作外包给“工作人员后端”(也称为Python)。在作业处理期间,作业会随着时间的推移经历不同的阶段(从“提交”到中间状态到“完成”,理想情况)。我想要实现的是实时向用户显示当前的作业状态。这意味着工作者后端必须将作业状态传递回Web应用程序。然后,Web应用程序必须将信息推送到用户的浏览器。我给你带了一张图片,示意性地描述了基本的想法: schematic problem description

红色圆圈中的数字表示事件的时间顺序。 “web app”和“worker backend”仍有待设计。现在,如果能帮助我做出一些技术决定,我将不胜感激。

我的问题,特别是:

  1. 我应该在网络应用和工作人员后端之间应用哪种消息传递技术? 当工作人员后端发出关于某个作业的信号(某种消息)时,它必须在Web应用程序中触发某个事件。因此,我需要某种与最初请求作业提交的客户端相关联的回调。我想我需要一些pub / sub机制,工作者后端发布,Web应用程序订阅。当Web应用程序收到消息时,它会通过向客户端发送状态更新来对其做出反应。我希望工作者后端可以扩展并与Web应用程序强烈分离。因此,我正在考虑使用Redis或ZeroMQ来完成这项任务。你怎么看?我的整个方法有点过于复杂吗?

  2. 我应该使用哪种技术将信息推送到浏览器? 出于完美主义,我希望得到实时更新。我不想以高频率进行民意调查。当工作人员后端发出消息时,我希望立即推送到客户端:-)。此外,我不需要最大的浏览器支持。这个项目首先或多或少是我自己的技术。我应该去HTML5服务器发送的事件/ websockets吗?或者你会推荐别的吗?

  3. 非常感谢您提前提出的建议。

3 个答案:

答案 0 :(得分:4)

一个选项是使用WebSocket。如果您走这条路,您可以查看Autobahn,其中包括Python(Twisted)的客户端和服务器,以及WebSocket上的RPC + PubSub协议(包含Python,JavaScript和Android的lib)。使用RPC + PubSub订阅可以保证重要的工作,并且可能符合您的需求(作业提交=> RPC,作业工作更新=> PubSub)。

AutobahnPython在Twisted上运行,它还可以充当WSGI容器,可以运行Flask(或其他基于WSGI的Web框架)。您可以在1端口/服务器上运行所有内容。 GitHub Autobahn存储库中有一个关于后者的例子。

免责声明:我是Autobahn的原创作者和WAMP,并为Tavendo工作。

<强>详细信息: 我假设你的工作人员做CPU密集和/或阻塞。

首先,您的工作人员是纯Python还是外部程序?

如果是后者,则可以使用Twisted进程协议实例,该实例通过stdio管道(以非阻塞方式)与主Twisted线程进行通信。如果是前者,则可以使用Twisted后台线程池并使用Twisted deferToThread(参见:http://twistedmatrix.com/documents/current/core/howto/threading.html)。

Autobahn在主要的Twisted反应器线程上运行。如果您的工作人员也这样做(请参阅之前的注释),那么您可以直接调用WebSocket / WAMP工厂/协议实例上的方法。如果不是(worker在后台线程上运行),你应该通过callFromThread调用这些方法。

如果你使用WAMP,最主要的是为每个工人获取WampServerFactory的参考。然后,工作人员可以通过调用适当的工厂方法将PubSub事件分派给所有订户。

答案 1 :(得分:3)

由于您正在讨论python Web应用程序,我建议您查看:

我应该在Web应用和工作人员后端之间应用哪种消息传递技术?

Celery - 将您的工作分解为较小的任务,这些任务会返回需要向客户显示的结果

我应该使用哪种技术将信息推送到浏览器?

Socket IO类型的服务器端JS框架上的NodeJSweb socket library for you python web framework

如果你没有过多地绑定python,请查看Meteor

基于this thread,实时更新从服务器到Web客户端的进度的其他方法可能包括将进度状态写入redis数据库或使用Oribited / Morbid(基于两者) Twisted)使用基于STOMP protocol

的异步结果的celery's subtasks

答案 2 :(得分:3)

任何用途,您的Web应用程序将拥有一个数据库。我会在该数据库中创建一个专门用于这些作业的表。你有一个&#39;州&#39;对于每份工作。

这简化了您的系统,因为您可以发送您的工作请求并将其移交给后端工作人员(zmq是此IMO的一个很好的解决方案)。由于您使用python作为后端,因此让您的工作人员更新其在数据库中的当前工作任务或者使用其他更新工具是非常简单的。其唯一的工作是更新数据库中的字段(保持逻辑分离将有助于更好的解决方案,允许您可能启动多个“更新程序”,如果您正在进行大量更新)

然后对于你的前端,因为你不想轮询服务器,我会做一些'long poll'。您实际上在做的是轮询服务器,但服务器实际上正在响应&#39;直到您感兴趣的数据发生变化。一旦发生变更,您就会回复此请求。在前端,您的JS会在收到最新更新后立即重新建立连接。这个解决方案是跨浏览器兼容的,只要你使用跨浏览器的JS框架(我建议使用jQuery)。


要消除Web应用程序数据库轮询,请执行以下操作:

将初始请求发送到Web应用程序的长轮询请求,Web应用程序向您的后端发送zmq消息(可能需要使用REQ / REP套接字)并等待。它等待直到从zmq后端收到状态更改的消息。当它获得状态更改时,它会响应更改前端。此时,前端将发出一个新的长轮询请求(此作业当前ID可以是其身份),Web应用程序将重新连接到后端并等待另一个状态更改。使这项工作的技巧是在最初创建套接字时(在第一个请求中)使用ZMQ的ZMQ_IDENTITY作为套接字。这将允许Web应用程序重新连接到同一后端套接字并获取新的更新。当后端有一个新的要发送的更新时,它将向Web应用程序发出信号,该应用程序又将响应长轮询请求及其状态更改。这样就没有polling,没有后端数据库,一切都是由后端工作人员驱动的。

我设置了某种看门狗,如果前端消失(切换页面或关闭浏览器),后端套接字将被正确关闭。当状态发生变化时,他们无需坐在那里无法阻挡。