我应该如何存储来自Django的长时间运行进程的状态?
我正在开发一个Django应用,允许用户上传文件。在把这些文件发送到亚马逊S3之前,我需要在服务器上对这些文件进行一些处理。看过关于这个问题的回答和这篇博客后,我决定最好的处理方式是让我的视图处理器调用Pyro远程对象的方法,异步地进行处理,然后立即返回一个Http 200的响应给客户端。我已经做了原型,似乎效果不错,但我还想存储处理的状态,以便客户端可以查询应用程序,看看文件是否已经处理并上传到S3。
我可以很容易地处理查询,但我不确定在哪里存储处理状态比较合适。这个状态需要能够被Pyro进程写入,同时也能被我的查询视图读取。
- 我不太想在数据库中添加列来存储那些其实只需要保留30到60秒的数据。
- 我考虑过使用Django的低级缓存API,用文件ID作为键,但我觉得这并不是缓存框架的设计初衷,也不确定这样做会有什么意想不到的问题。
- 最后,我考虑过把状态存储在处理的Pyro对象中,但这样看来,我还是需要在数据库中添加一个布尔值“processing_complete”列,以便视图知道是否需要从Pyro对象查询状态。
当然,把状态和数据库分开存储也会有一些数据完整性的问题(如果服务器崩溃了,这些数据都在内存中怎么办?)。我想听听更有经验的网页应用开发者会如何处理这种有状态的处理。
3 个回答
所以,你需要的是一个工作队列。在你的情况下,我建议使用数据库来保存状态,即使这些状态存在的时间很短。听起来这样可以满足你的所有需求,而且实现起来也不是特别难,因为你已经有了所有必要的部分。保持简单,除非你真的需要更复杂的东西。
如果你需要更强大或更复杂的东西,我建议你看看 Gearman。
我们在数据库里有一个“请求”表来处理这个问题。
当文件上传到来时,我们会创建一个文件对象,并同时创建一个请求记录。
接着,我们启动一个后台处理程序。
然后,我们返回一个200的页面,告诉用户“我们正在处理中”——这个页面会显示请求和它们的状态。
我们的后台处理程序使用Django的ORM工具。当处理完成后,它会更新请求记录。我们可以选择发送邮件通知用户,但通常我们只是更新状态,让用户可以再次登录查看处理是否完成。
关于批处理服务器架构的说明。
这是一个WSGI服务器,它在某个端口上等待批处理请求。这个请求是一个带有ID号的REST POST请求;批处理程序会在数据库中查找这个ID并进行处理。
服务器是通过我们的REST接口自动启动的。如果它没有运行,我们会启动它。这可能会让用户的操作感觉比较慢,不过没办法。它不应该崩溃。
此外,我们还有一个简单的定时任务(crontab)来检查它是否在运行。最多会在“你还活着吗?”的检查之间停机30分钟。我们没有正式的启动脚本(我们是在Apache下用mod_wsgi运行的),但我们可能会创建一个“重启”脚本,更新WSGI文件,然后向一个健康检查的URL发送POST请求(并启动批处理程序)。
当批处理服务器启动时,可能会有一些未处理的请求,因为它之前没有收到POST请求。所以,默认的启动方式是从请求队列中提取所有的工作——假设它可能错过了什么。