我该如何为从Django调用的长时间运行的进程存储状态?

5
我正在开发一个Django应用程序,允许用户上传文件。在将这些文件发送到Amazon S3之前,我需要对它们进行一些服务器端处理。阅读这个问题这篇博客文章的回复后,我决定最好的处理方式是让我的视图处理程序调用Pyro远程对象上的方法异步执行处理,然后立即向客户端返回Http 200。我已经完成了这个原型,并且似乎工作得很好,但是,我还想存储处理状态,以便客户端可以轮询应用程序,查看文件是否已被处理并上传到S3。

我可以很容易地处理轮询,但我不确定存储过程状态的适当位置在哪里。它需要由Pyro进程可写,由我的轮询视图可读取。

  • 我不确定是否应该为只需保留30至60秒的数据向数据库添加列。
  • 我考虑使用Django的低级缓存API,并使用文件ID作为键,但我不认为这是缓存框架的设计目的,而且我也不确定采用这种方法会有什么未预料到的问题。
  • 最后,我考虑在执行处理的Pyro对象中存储状态,但这似乎仍然需要添加一个布尔型“processing_complete”数据库列,以便视图知道是否从Pyro对象查询状态。

当然,将状态与数据库解耦也存在一些数据完整性方面的问题(如果服务器崩溃,所有这些数据都在内存中会发生什么?)。我很想听听更有经验的Web应用程序开发人员如何处理这种有状态的处理。

3个回答

6
我们实现这个功能的方法是在数据库中创建了一个“请求”表。
当上传到达时,我们创建上传的文件对象,并创建一个请求。
我们启动后台批处理器。
我们返回一个200“正在处理中”的页面--它显示请求及其状态。
我们的批处理器使用Django ORM。完成后,它会更新请求对象。我们可以(但不必)发送电子邮件通知。主要是更新状态,以便用户可以再次登录并查看处理已完成。
批处理服务器架构说明。
它是一个WSGI服务器,等待批处理请求的端口。该请求是带有ID号的REST POST;批处理器在数据库中查找它并进行处理。
服务器由我们的REST接口自动启动。如果它没有运行,我们就会将其生成。这使得用户交易似乎很慢,但是,哦好吧。它不应该崩溃。
此外,我们有一个简单的crontab来检查它是否在运行。最多,在“你还活着吗?”检查之间会停止30分钟。我们没有正式的启动脚本(我们在Apache下运行mod_wsgi),但我们可能会创建一个“重新启动”脚本,它会触摸WSGI文件,然后对执行健康检查的URL进行POST(并启动批处理器)。
当批处理服务器启动时,可能存在从未收到POST请求的未处理请求。因此,默认启动是从请求队列中提取所有工作--假设可能会错过某些内容。

经过一夜的思考,我决定你是完全正确的。不使用数据库就没有意义。我也决定Pyro在这里不适合,我应该像普通人一样使用带有锁文件的cron作业。 - bouvard
我觉得我应该把上一条评论表达成一个问题,因为显然你有处理这个问题的方法:你的策略是什么? - bouvard
我们不喜欢频繁的crontab轮询请求。每隔几分钟就在数据库中执行SELECT会增加太多开销。由于这些请求相对较少,因此我们使用WSGI服务器的RESTful通知。 - S.Lott
啊,我明白了。在我的情况下恰恰相反。上传对于应用程序来说是至关重要的,因此处理请求可能会变得非常频繁。尽管我尽力避免使用cron(更多是出于哲学原因而不是其他任何原因),但我认为这是一个明智的解决方案。 - bouvard
我们的批处理服务器有一个小的客户端 API 包,主要的 Web 应用程序使用它。该客户端 API 包通常使用 urllib2 发起请求。如果无法建立连接,则使用 subprocess 来生成批处理服务器,然后发起请求。然后 Web 应用程序会发送 200,而不管批处理服务器实际上是否已经完成。 - S.Lott
显示剩余4条评论

5

虽然这是一个老问题,但即使经过了这么长时间,有人可能仍然会发现我的答案有用,所以我来回答一下。

当然,您可以使用数据库作为队列,但也有专门为此目的开发的解决方案。

AMQP 就是其中之一。它可以和 Celery 或者 Carrot 一起使用,并使用像 RabbitMQ 或者 ZeroMQ 这样的代理服务器。

这正是我们在最新项目中使用的方式,而且效果非常好。

对于您的问题,Celery 和 RabbitMQ 看起来是最合适的选择。 RabbitMQ 可以提供消息的持久性,而 Celery 则公开了易于轮询的视图,以检查并行运行的进程的状态。

您可能还对octopy感兴趣。


1

所以,你需要一个工作队列。对于你的情况,我绝对会选择使用数据库来保存状态,即使这些状态是短暂的。听起来这将满足你所有的要求,并且由于你已经拥有了所有的移动部件,因此实现起来并不是非常困难。除非你需要更复杂的东西,否则保持简单。

如果你需要更强大或更复杂的东西,我建议看看Gearman


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接