Cron与virtualenv

323 投票
20 回答
179621 浏览
提问于 2025-04-16 01:33

我正在尝试通过定时任务(cron)运行一个Django管理命令。我使用虚拟环境(virtualenv)来保持我的项目独立。

我在这里和其他地方看到了一些示例,展示了如何在虚拟环境中运行管理命令,比如:

0 3 * * * source /home/user/project/env/bin/activate && /home/user/project/manage.py command arg

但是,尽管系统日志(syslog)显示在任务应该开始时有记录,这个任务实际上并没有运行(脚本的日志文件是空的)。如果我在命令行手动运行这行命令,它是可以正常工作的。

目前,我能通过定时任务运行命令的唯一方法是把命令拆开,放在一个简单的bash脚本里:

#!/bin/sh
source /home/user/project/env/bin/activate
cd /home/user/project/
./manage.py command arg

编辑:

ars 提供了一组有效的命令组合:

0 3 * * * cd /home/user/project && /home/user/project/env/bin/python /home/user/project/manage.py command arg

至少在我的情况下,调用虚拟环境的激活脚本并没有起作用。这个方法有效,所以我们继续吧。

20 个回答

41

抱歉再说一次这个问题的答案,但我查看了其他答案,发现其实有更简单、更清晰的方法。

简单来说

在你的定时任务(cron)中使用你虚拟环境里的Python:

0 3 * * * /home/user/project/env/bin/python /home/user/project/manage.py 

详细说说

我们在想要使用特定虚拟环境的Python配置时,会激活这个虚拟环境。这样做的好处是可以在当前的命令行中直接执行多个Python命令,而不需要每次都输入虚拟环境的完整路径。
那么在定时任务或者bash脚本中,应该怎么激活这个环境呢?我看到有些答案提到用bash而不是sh,或者还要定义一个包装器来调用Python代码。但为什么要这么麻烦呢?

我再说一遍,直接这样做就行:

0 3 * * * /home/user/project/env/bin/python /home/user/project/manage.py 

官方文档确认了这一点:

你并不一定需要激活一个环境;激活只是将虚拟环境的二进制目录添加到你的路径中,这样“python”就会调用虚拟环境的Python解释器,你可以运行安装的脚本而不需要使用它们的完整路径。不过,所有在虚拟环境中安装的脚本都应该可以在不激活环境的情况下运行,并且会自动使用虚拟环境的Python。

140

在cron文件中运行source是行不通的,因为cron默认使用的shell是/bin/sh,而这个shell不支持source命令。你需要把SHELL环境变量设置为/bin/bash

SHELL=/bin/bash
*/10 * * * * root source /path/to/virtualenv/bin/activate && /path/to/build/manage.py some_command > /dev/null

要找出为什么会失败其实很棘手,因为/var/log/syslog并不会记录错误的详细信息。最好的办法是把自己设置为root用户,这样你就能收到任何cron错误的邮件。只需把自己添加到/etc/aliases中,然后运行sendmail -bi

更多信息可以在这里找到: http://codeinthehole.com/archives/43-Running-django-cronjobs-within-a-virtualenv.html

上面的链接已更改为: https://codeinthehole.com/tips/running-django-cronjobs-within-a-virtualenv/

340

你可以在你的虚拟环境中使用 python 来做到这一点:

/home/my/virtual/bin/python /home/my/project/manage.py command arg

补充一下:如果你的 Django 项目不在 PYTHONPATH 中,那么你需要切换到正确的目录:

cd /home/my/project && /home/my/virtual/bin/python ...

你也可以尝试记录一下 cron 任务失败的信息:

cd /home/my/project && /home/my/virtual/bin/python /home/my/project/manage.py > /tmp/cronlog.txt 2>&1

另一个可以尝试的方法是在你的 manage.py 脚本的最顶部做同样的修改:

#!/home/my/virtual/bin/python

撰写回答