Cron和virtualenv

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

我在这里和其他地方看到了从virtualenv中运行管理命令的示例,例如:

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

然而,尽管syslog显示了任务应该在何时启动的条目,但该任务从未实际运行(脚本的日志文件为空)。如果我从shell中手动运行这一行,它将按预期工作。

我目前可以通过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的激活脚本没有任何作用。这招管用,所以节目继续。

153222 次浏览

你应该能够通过在你的虚拟环境中使用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

从cronfile中运行source将不起作用,因为cron使用/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 < / p >

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

与其在特定于virtualenv的shebangs上瞎折腾,还不如在crontab上前置PATH

在激活的virtualenv中,运行这三个命令,python脚本就可以工作了:

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

crontab的第一行现在应该是这样的:

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

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

一种方法是在python脚本中使用virtualenv的activate_this,参见: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

对我来说,最好的解决办法是两者兼得

  • 使用venv bin/目录下的python二进制文件
  • 设置python路径 要包含venv模块目录

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
>>>

不用再看了:

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

这样做的好处是你不需要将crontab的SHELL变量从sh更改为bash

我想添加这一点,因为我花了一些时间解决这个问题,并没有在这里找到一个答案,在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 /激活”

感谢@davidwinterbottom@reed-sandberg@mkb给了正确的方向。接受的答案实际上工作得很好,直到你的python需要运行一个脚本,必须从venv/bin目录运行另一个python二进制文件。

这是一个对我很有效的解决办法。

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运行它,没有任何麻烦。

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 * * * * -每一分钟执行一次
  • / testcron / cd /工作空间 - python脚本的路径
  • / Workspace / testcron / venvcron / bin / python3 - Virtualenv路径
  • 工作区/ testcron / testcronwithparam.py -文件路径
  • 参数参数

如果你使用python并且使用Conda虚拟环境(其中python脚本包含shebang # !/usr/bin/env python),则以下工作:

* * * * * cd /home/user/project && /home/user/anaconda3/envs/envname/bin/python script.py 2>&1

此外,如果你想在你的脚本中捕获任何输出(例如打印,错误等),你可以使用以下命令:

* * * * * cd /home/user/project && /home/user/anaconda3/envs/envname/bin/python script.py >> /home/user/folder/script_name.log 2>&1

我已经在我的Django项目中添加了下面的脚本manage.sh,它源virtualenv,然后运行manage.py脚本,不管你传递给它什么参数。它使得在virtualenv (cron, systemd单元,基本上任何地方)中运行命令变得非常容易:

#! /bin/bash


# this is a convenience script that first sources the venv (assumed to be in
# ../venv) and then executes manage.py with whatever arguments you supply the
# script with. this is useful if you need to execute the manage.py from
# somewhere where the venv isn't sourced (e.g. system scripts)


# get the script's location
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"


# source venv <- UPDATE THE PATH HERE WITH YOUR VENV's PATH
source $DIR/../venv/bin/activate


# run manage.py script
$DIR/manage.py "$@"

然后在你的cron条目中运行:

0 3 * * * /home/user/project/manage.sh command arg

只要记住,你需要使manage.sh脚本可执行

由于cron在它自己的最小sh环境中执行,下面是我在虚拟环境中运行Python脚本的方法:

* * * * * . ~/.bash_profile; . ~/path/to/venv/bin/activate; python ~/path/to/script.py

(注意:如果. ~/.bash_profile不适合你,那么根据你的服务器的设置,尝试. ~/.bashrc. ~/.profile。)

这将加载您的bash shell环境,然后激活您的Python虚拟环境,基本上为您留下与测试脚本相同的设置。

不需要在crontab中定义环境变量,也不需要修改现有脚本。

这也适用于crontab -e

* */5 * * * cd /home/project && sudo /home/project/venv/bin/python scripte.py

我也有同样的问题:

我写了一个自定义的django命令来检查geodjango多边形内部的geodjango位置坐标,并且在自动化任务运行时遇到了麻烦,然而使用crontab这个命令对我来说是有效的:

* * * * * ./home/project/locations/locations.sh >> /var/log/locations.log 2>&1

这是一种保持crontab命令与常规命令非常相似的简单方法(在Ubuntu 18.04中进行了测试)。一些需要记住的关键注意事项:

  • 你可以使用.命令代替source。(crontab默认使用sh,而不是bash,所以它没有source。)
  • ~$variables在crontab命令中展开。(只有crontab环境语句不进行变量展开。)

下面是一个例子,如果你有一个文件~/myproject/main.py:

* * * * * cd ~/myproject && . .venv/bin/activate && python main.py > /tmp/out1 2>&1

你也可以直接调用venv目录中python的特定路径,这样就不需要调用activate了。

* * * * * ~/myproject/.venv/bin/python ~/myproject/main.py > /tmp/out2 2>&1

这样做的缺点是您需要指定两次项目路径,这使得维护更加棘手。为了避免这种情况,你可以使用一个shell变量,这样你只指定一次项目路径:

* * * * * project_dir=~/myproject ; $project_dir/.venv/bin/python $project_dir/main.py > /tmp/out3 2>&1

我很抱歉第n个答案,但我检查了答案,确实有更简单和整洁的答案。

长话短说

在你的cron中使用venv的python二进制文件:

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

很长的故事

当我们想要使用特定虚拟环境的python配置(即二进制文件和模块)设置当前shell时,我们激活虚拟环境。
这与使用当前shell有关:在当前shell上执行多个python命令,而不需要引用venv的完整python路径。
在cron甚至bash的框架中,哪个值激活环境? 此外,我在一些回答中读到一些引用bash而不是sh,或者仍然定义一个包装器来调用Python代码。但是我们为什么要麻烦这些?

重复一遍,照做就好:

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

文档确认:

你不需要特别激活一个环境;激活 只需将虚拟环境的二进制目录前置到您的路径, 这样" python "就会调用虚拟环境的python解释器 您可以运行已安装的脚本,而不必使用它们的全部 路径。但是,在虚拟环境中安装的所有脚本都应该 在不激活它的情况下也可以运行,并使用虚拟机运行

我也有同样的问题,花了很多时间来解决。 这里没有一个解决方案对我有用,所以我分享了对我有用的:

  1. 打开一个新文件“;pick_name.sh”;在项目目录中打开它。
  2. 在“;pick_name.sh”;文件,写入并保存以下行:
#!/bin/bash
source /YOUR_VIRTUAL_ENV_PATH/bin/activate
export PYTHONPATH="${PYTHONPATH}:/PATH_TO_CUSTOM_MODULE_YOU_CREATED**OPTIONAL**"
export PYTHONPATH="${PYTHONPATH}:/PATH_TO_ANOTHER_CUSTOM_MODULE_YOU_CREATED**OPTIONAL**"
cd /PATH_TO_DIR_STORING_FILE_NAME.PY
python file_name.py
  1. 转到/var/spool/cron/crontabs(或到您的cron管理文件所在的位置)并打开“根”文件。
  2. 将这些行添加到crontab文件夹中的根文件中:
# m h  dom mon dow   command
* * * * * /PATH_TO_DIR_WHERE_PICK_NAME.SH_SITS/pick_name.sh >> /YOUR_PROJECT_DIR/cron_output.txt 2>&1

注:

  • 这个命令(第4节)将运行“;pick_name.sh”;文件。 在本例中,它每分钟运行一次,因此请确保根据需要更改它。 它将所有日志写到一个名为“cron_output”的日志文件中。 之前不需要创建文件,它会自动创建
  • 确保将所有路径(我用大写字母写的)替换为您的路径。
  • 您可以更改文件名,如果是这样,请确保在我的指示中更改所有外观,以避免错误。
  • 如果你想添加另一个由cron运行的py文件,你需要将它添加到“pick_nam.sh"文件*而不是cron。简单地复制第2部分。pick_nam.sh"但是没有“#!/bin/bash”;部分。 然后,每次cron都会运行“pick_name.sh”;它将运行你在其中指定的所有文件
  • 修改后一定要重新启动cron,这可以节省我很多调试时间,使用这个命令:
systemctl restart cron

在venv中添加Python安装路径,但不要激活环境。

* * * * * /HDD1/shritam_kumar/VENOM/venv/bin/python /HDD1/shritam_kumar/Projects/Voelkner-DE/schedule_product_BA.py

就是这么简单。

如果你和我一样是MacOS用户,你可以在/var/mail/{username}文件中查看crontab错误信息。像这样

tail /var/mail/{username}

如果有“不允许操作”;错误,也许你必须添加cron到全磁盘访问应用程序(安全&隐私比;隐私比;全磁盘访问应用程序/execs)。

然后点击+按钮,进入/usr/sbin,双击cron文件。 然后,它将修复“不允许”;错误。详细步骤 < / p >

这是我的代码:

0 19 * * * cd /Users/user/Desktop/Project && source /Users/user/Desktop/Project/venv/bin/activate && python command arg