3

我正在开发的 Web 应用程序需要执行在 http 请求/响应周期中执行时间过长的任务。通常,用户将执行请求,服务器将接受此请求,除其他外,运行一些脚本以生成数据(例如,使用 povray 渲染图像)。

当然,这些任务可能需要很长时间,因此在将响应发送给客户端之前,服务器不应该挂起等待脚本完成执行。因此,我需要异步执行脚本,并给客户端一个“资源在这里,但尚未准备好”,并可能告诉它一个 ajax 端点进行轮询,以便它可以在准备好时检索和显示资源。

现在,我的问题与设计无关(尽管我也非常喜欢这方面的任何提示)。我的问题是:解决这个问题的系统是否已经存在,所以我不重新发明方轮?如果必须,我会使用进程队列管理器来提交任务并放置一个 HTTP 端点来输出状态,比如“待定”、“中止”、“完成”给 ajax 客户端,但如果已经有类似的东西专门为这项任务而存在,我最喜欢它。

我在 python+django 工作。

编辑:请注意这里的主要问题不是服务器和客户端必须如何协商和交换有关任务状态的信息。

问题是服务器如何处理非常长的任务的提交和排队。换句话说,我需要一个比让我的服务器在LSF上提交脚本更好的系统。不是说不行,而是我觉得有点过分了……

编辑2:我添加了一个赏金,看看我是否能得到其他答案。我检查了 pyprocessing,但我无法提交作业并在稍后阶段重新连接到队列。

4

7 回答 7

4

您应该避免在这里重新发明轮子。

检查齿轮人。它有很多语言(包括python)的库,并且相当流行。不确定是否有人有任何开箱即用的方法可以轻松地将 django 连接到 gearman 和 ajax 调用,但自己做这部分不应该很复杂。

基本思想是您运行 gearman 作业服务器(或多个作业服务器),让您的 Web 请求使用一些参数(例如 '{photo_id: 1234}')排队一个作业(例如 'resize_photo')。您将其作为后台任务排队。你得到一个把手回来。然后,您的 ajax 请求将轮询该句柄值,直到它被标记为完成。

然后你有一个工人(或可能很多)是一个单独的 python 进程连接到这个作业服务器并为'resize_photo'作业注册自己,完成工作,然后将其标记为完成。

我还发现这篇博客文章很好地总结了它的用法。

于 2009-12-02T02:22:16.967 回答
1

您可以尝试两种方法:

  • 每隔n间隔调用一次 webserver并通知一个作业 id;服务器进程并返回有关该任务当前执行的一些信息
  • 实现一个长时间运行的页面,每隔n个间隔发送一次数据;对于客户端,该 HTTP 请求将“始终”存在,并且每次收到新数据时它都需要收集新信息。"loading"

关于第二个选项,您可以通过阅读Comet了解更多信息;使用 ASP.NET,您可以通过实现System.Web.IHttpAsyncHandler接口来做类似的事情。

于 2009-11-17T12:07:25.967 回答
1

我不知道有什么系统可以做到这一点,但是实现自己的系统会相当容易:

  • 使用 jobid、jobparameters、jobresult 创建一个数据库表
    • jobresult 是一个字符串,将保存结果的泡菜
    • jobparameters 是输入参数的腌制列表
  • 当服务器开始工作时,它会在表中创建一个新行,并创建一个新进程来处理它,并传递给该进程 jobid
  • 任务处理程序完成后更新表中的作业结果
  • 网页(xmlrpc 或您正在使用的任何内容)包含一个方法“getResult(jobid)”,它将检查表中的作业结果
    • 如果找到结果,则返回结果,并从表中删除该行
    • 否则它会返回一个空列表,或 None,或您的首选返回值,以表明作业尚未完成

有一些边缘情况需要处理,因此现有框架显然会更好,如您所说。

于 2009-11-30T07:18:35.453 回答
1

首先,您需要一些单独的“worker”服务,该服务将在开机时单独启动,并通过一些本地 IPC(如 UNIX-socket(快速)或数据库(简单))与 http-request 处理程序进行通信。

在处理请求期间,cgi 从工作状态或其他数据中询问并重播给客户端。

于 2009-12-01T11:23:10.950 回答
0

python 和 django 的另一个不错的选择是Celery

如果你认为 Celery 对你的需求来说太重了,那么你可能想看看简单的分布式任务队列

于 2012-02-18T15:18:34.543 回答
0

您可以通过回复 202 HTTP 代码来表示资源正在“处理”:客户端必须稍后重试才能获得完整的资源。根据具体情况,您可能必须发出“请求 ID”才能将请求与响应匹配。

或者,您可以查看现有的 COMET 库,这些库可能更“开箱即用”地满足您的需求。我不确定是否有任何与您当前的 Django 设计相匹配的。

于 2009-11-17T12:23:54.653 回答
0

对于您正在使用的 python/django 解决方案,可能不是一个很好的答案,但我们使用 Microsoft Message Queue 来处理这样的事情。它基本上是这样运行的

  1. 网站在某处以“处理中”状态更新数据库行
  2. 网站向 MSMQ 发送消息(这是一个非阻塞调用,因此它会立即将控制权返回给网站)
  3. Windows 服务(实际上可以是任何程序)正在“监视”MSMQ 并获取消息
  4. Windows 服务以“已完成”状态更新数据库行。

无论如何,这就是它的要点。它对我们来说非常可靠,并且可以直接扩展和管理。

-al

于 2009-12-02T02:39:57.610 回答