我能在Django中像守护进程一样持续运行代码吗
我正在用mod_wsgi通过Apache来运行一个Django网站。同时,我还有一些Python代码,它作为后台进程在运行(是不是叫守护进程?)。这段代码不断地去查询一个服务器,并把数据插入到Django的一个模型里。这一切都运行得很好,但我想知道能不能把这段代码放到我的Django应用里,并且让它一直在后台运行?它不一定要是一个独立的进程,而是Django网站的一部分,能够持续活跃。如果可以的话,能不能给我指个例子或者一些文档,帮助我实现这个目标?
谢谢。
3 个回答
我之前用过定时任务(cron job),但我告诉你,过一段时间你就会转向使用Celery了。
Celery才是正道。而且你可以把一些耗时的异步任务交给它处理,这样可以加快请求和响应的速度。
你可以在首次导入WSGI脚本时创建一个后台线程。
import threading
import time
def do_stuff():
time.sleep(60)
... do periodic job
_thread = threading.Thread(target=do_stuff)
_thread.setDaemon(True)
_thread.start()
不过,要让这个方法有效,你必须只使用一个守护进程,否则每个进程都会做同样的事情,这可能不是你想要的。
如果你在守护进程组中使用多个进程,另一种选择是创建一个特殊的守护进程组,专门用来运行这个后台线程。换句话说,这个进程实际上并不接收任何请求。
你可以通过以下方式来实现:
WSGIDaemonProcess django-jobs processes=1 threads=1
WSGIImportScript /usr/local/django/mysite/apache/django.wsgi \
process-group=django-jobs application-group=%{GLOBAL}
WSGIImportScript指令是告诉系统加载这个脚本,并在'django-jobs'进程组的上下文中启动它。
为了避免使用多个脚本,我将它指向你原本用于WSGIScriptAlias的WSGI脚本文件。不过,我们不希望它在被这个指令加载时就运行,所以我们这样做:
import mod_wsgi
if mod_wsgi.process_group == 'django-jobs':
_thread = threading.Thread(target=do_stuff)
_thread.setDaemon(True)
_thread.start()
这里,它会查看守护进程组的名称,只有在这个专门为此设置的单进程守护进程组中启动时才会运行。
总体来说,你只是把Apache当作一个强大的进程管理器来用,虽然它本身已经很稳定了。这种做法有点过于复杂,因为这个进程会消耗额外的内存,除了那些接收和处理请求的进程之外,但根据你所做事情的复杂性,这仍然可能是有用的。
这样做的一个有趣之处在于,由于它仍然是一个完整的Django应用程序,你可以将特定的URL映射到这个进程,从而提供一个远程API来管理或监控后台任务及其执行情况。
WSGIDaemonProcess django-jobs processes=1 threads=1
WSGIImportScript /usr/local/django/mysite/apache/django.wsgi \
process-group=django-jobs application-group=%{GLOBAL}
WSGIDaemonProcess django-site processes=4 threads=5
WSGIScriptAlias / /usr/local/django/mysite/apache/django.wsgi
WSGIProcessGroup django-site
WSGIApplicationGroup %{GLOBAL}
<Location /admin>
WSGIProcessGroup django-jobs
</Location>
在这里,除了/admin下的内容,所有的URL都在'django-site'中,而/admin则在'django-jobs'中。
无论如何,这解决了在Apache mod_wsgi守护进程中执行的具体问题。
如前所述,另一种选择是使用命令行脚本来设置和加载Django并执行任务,然后通过cron作业来运行这个脚本。命令行脚本意味着偶尔会使用一些临时内存,但每次启动任务时的开销会更高,因为需要每次都加载所有内容。
你可以设置一个定时任务,让它定期运行你定义的某个功能,或者更高级一点的方法,就是在你的项目中集成celery(其实这也很简单)。