Cron和virtualenv


227

我正在尝试从cron运行Django管理命令。我正在使用virtualenv使我的项目沙盒化。

我在这里和其他地方都看到了一些示例,这些示例显示了从virtualenv内部运行的管理命令,例如:

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

但是,即使syslog在任务应该启动时显示一个条目,该任务也不会实际运行(脚本的日志文件为空)。如果我从外壳程序手动运行该行,它将按预期工作。

目前,我可以使命令通过cron运行的唯一方法是将这些命令分解并放在一个笨拙的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

至少就我而言,为virtualenv调用激活脚本没有任何作用。这是可行的,因此在演出中如此。


我看到的一个区别是,该脚本将使用/ home / user / project作为当前工作目录运行manage.py。您的cron命令将以您的主目录作为cwd运行。也许日志文件在那里?

实际上,日志路径是绝对定义的,因为脚本未运行,所以根本不会创建/添加该路径。
约翰·斯科特

解决cron问题的一种快速而肮脏的解决方案是转储您的环境(在该环境中,您的命令无法正常工作),env并将export它们全部转储到您从crontab调用的bash脚本包装中。
jberryman 2012年

Answers:


250

您应该可以通过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

1
那也行不通。忘了把那放在我不起作用的事情清单中。是的,我可以在外壳中手动运行该命令,但不能在cron中运行。
约翰·斯科特

~用完整路径代替了吗?(您可能没有,只是确保...)
ARS

啊,您想出了一个可行的例子!我已经尝试过每种组合,并且激活virtualenv似乎没有任何效果。我的确在.bashrc中设置了我的PYTHONPATH,但是cron显然没有使用它?将更新我的问题以突出您的答案。
John-Scott 2010年

是的,我忘记了cron在非常小的环境下运行。一般建议是编写bash脚本来设置您的工作需要的任何环境。您可以尝试直接在cron中采购bash配置文件,但这可能会导致细微的错误,具体取决于配置文件中的内容(也许如果您有单独的且最小的配置文件可以满足此类需求)。
ARS

7
测试的好方法是执行/ bin / sh,然后尝试从那里执行命令。至少您将拥有与cron相同的环境设置。
迪克(Dick)

98

source从cronfile 运行将无法正常运行,因为cron /bin/sh用作其默认外壳程序,该外壳程序不支持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/


12
要么 '。' (点命令),由/ bin / sh支持. /path/to/virtualenv/bin/activate
Reed Sandberg 2014年

5
DavidWinterbottom,如果那是您的真名,那您就是我的英雄。我从不知道关于sh vs bash和源文件。您已经为我的bash脚本编写小家伙们照亮了光芒。谢谢。
joemurphy '16

如果您有postactivate文件,则应该这样做source /path/to/virtualenv/bin/activate && source /path/to/virtualenv/bin/postactivate
dspacejs,2016年

1
谢谢!对我而言,这行之有效,而不是杰拉尔德接受的答案。
马丁·贝克尔

1
“根”的作用是什么?
谁能

19

不要再看了:

0 3 * * * /usr/bin/env bash -c 'cd /home/user/project && source /home/user/project/env/bin/activate && ./manage.py command arg' > /dev/null 2>&1

通用方法:

* * * * * /usr/bin/env bash -c 'YOUR_COMMAND_HERE' > /dev/null 2>&1

这样做的好处是您无需将SHELLcrontab 的变量从更改shbash


13

使用virtualenv时,运行python cron作业的唯一正确方法是激活环境,然后执行环境的python来运行代码。

一种方法是activate_this在您的python脚本中使用virtualenv ,请参阅:http : //virtualenv.readthedocs.org/en/latest/userguide.html#using-virtualenv-without-bin-python

另一个解决方案是回显完整的命令,包括激活环境并将其传递到/bin/bash。考虑为您的/etc/crontab

***** root echo 'source /env/bin/activate; python /your/script' | /bin/bash

1
对于是否达成共识,这实际上是唯一正确的方法,我感到很好奇。
亚伦·舒马赫

1
这可能是唯一正确的方法。但是还有其他可行的方法。
2015年

4
这不是“唯一正确的方法”。我已经成功地在virtualenv中执行了一个脚本,只需将cronjob指向virtualenv的python二进制文件,例如'/ home / user / folder / env / bin / python'。无需激活任何环境。
Canucklesandwich,2015年

如果您在虚拟环境中使用自定义PYTHONPATH,则env / bin / python对您不起作用。这就是为什么使用env / bin / activate更好的原因
varela 2015年

1
这取决于您如何设置PYTHONPATH,并且如果您以要求“激活” venv的方式进行设置,那么您做错了

10

与其摆弄特定于virtualenv的shebang,不如摆PATH在crontab上。

在激活的virtualenv中,运行以下三个命令,并且python脚本应该可以正常工作:

$ echo "PATH=$PATH" > myserver.cron
$ crontab -l >> myserver.cron
$ crontab myserver.cron

现在,crontab的第一行应如下所示:

PATH=/home/me/virtualenv/bin:/usr/bin:/bin:  # [etc...]

12
不是一个好的解决方案。然后,crontab中的每个python任务都将与virtualenv中的二进制文件一起运行。使该二进制文件成为伪全局 python违反了virtualenv的目的。
维克托·施罗德(VictorSchröder)

4

对我来说最好的解决方案是

  • 使用venv bin /目录中的python二进制文件
  • 设置python路径以包含venv modules目录。

man python提到使用以下命令在shell中$PYTHONPATH或在python 中修改路径sys.path

其他答案提到使用shell进行此操作的想法。在python中,将以下行添加到我的脚本中使我可以直接从cron成功运行它。

import sys
sys.path.insert(0,'/path/to/venv/lib/python3.3/site-packages');

这是交互式会话中的外观-

Python 3.3.2+ (default, Feb 28 2014, 00:52:16) 
[GCC 4.8.1] on linux
Type "help", "copyright", "credits" or "license" for more information.

>>> import sys

>>> sys.path
['', '/usr/lib/python3.3', '/usr/lib/python3.3/plat-x86_64-linux-gnu', '/usr/lib/python3.3/lib-dynload']

>>> import requests
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named 'requests'   

>>> sys.path.insert(0,'/path/to/venv/modules/');

>>> import requests
>>>

4

我想添加这个内容是因为我花了一些时间解决问题,但在这里找不到cron和virtualenv中变量使用组合的答案。所以也许会帮助某人。

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DIR_SMTH="cd /smth"
VENV=". venv/bin/activate"
CMD="some_python_bin do_something"
# m h  dom mon dow   command
0 * * * * $DIR_SMTH && $VENV && $CMD -k2 some_target >> /tmp/crontest.log 2>&1

像这样配置时效果不佳

DIR_SMTH =“ cd / smth &&。venv / bin / activate”

感谢@ davidwinterbottom@ reed-sandberg@mkb提供正确的方向。在您的python需要运行一个脚本(该脚本必须从venv / bin目录运行另一个python二进制文件)之前,可接受的答案实际上可以正常工作。


0

这是一个对我有效的解决方案。

source /root/miniconda3/etc/profile.d/conda.sh && \
conda activate <your_env> && \
python <your_application> &

我在Ubuntu 18.04.3 LTS上使用带有Conda版本4.7.12的miniconda。

我可以将以上内容放入脚本中,并通过crontab进行运行,而不会遇到任何麻烦。


0

python脚本

from datetime import datetime                                                                                                                                                                
import boto   # check wheather its taking the virtualenv or not                                                                                                                                                                        
import sys                                                                                                                                                                                   
param1=sys.argv[1]     #Param                                                                                                                                                                                                                                                                                                                                                                    
myFile = open('appendtxt.txt', 'a')                                                                                                                                                      
myFile.write('\nAccessed on ' + param1+str(datetime.now())) 

Cron命令

 */1 * * * *  cd /Workspace/testcron/ && /Workspace/testcron/venvcron/bin/python3  /Workspace/testcron/testcronwithparam.py param  

在上面的命令中

  • * / 1 * * * * -每1分钟执行一次
  • cd / Workspace / testcron /-python脚本的路径
  • / Workspace / testcron / venvcron / bin / python3 -Virtualenv路径
  • Workspace / testcron / testcronwithparam.py-文件路径
  • 参数 -参数
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.