我正在尝试从 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 调用激活脚本什么也没做。这行得通,以此类推。
env
和 export
将您的环境(在其中您的命令莫名其妙地工作)转储到您从 crontab 调用的 bash 脚本包装器中。
您应该能够通过在虚拟环境中使用 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
作为其不支持 source
的默认 shell。您需要将 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/
. /path/to/virtualenv/bin/activate
支持
root
用户及其权限(万王之王)。 cronjob 计时后的第一列是执行 cronjob 的用户。
不要再看了:
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
bash -c
是不必要的。只需使用 .
命令而不是 source
。您无需更改 crontab 中的 SHELL 变量,或使用 bash -c
包装您的命令。请参阅stackoverflow.com/questions/3287038/cron-and-virtualenv/…
cd /home/user/project && source /home/user/project/env/bin/activate && ./manage.py command arg
使用 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
.
命令而不是 source
。请参阅stackoverflow.com/questions/3287038/cron-and-virtualenv/…
我很抱歉第 n 个答案,但我检查了答案,确实更简单、更整洁。
长话短说
在 cron 中使用 venv 的 python 二进制文件:
0 3 * * * /home/user/project/env/bin/python /home/user/project/manage.py
很长的故事
当我们想要使用特定虚拟环境的 python 配置(即二进制文件和模块)设置当前 shell 时,我们会激活虚拟环境。
与当前 shell 的工作相关:在上执行多个 python 命令当前 shell 不需要引用 venv 的完整 python 路径。
在 cron 甚至 bash 的框架中,激活环境的值是什么?此外,我在一些答案中读到了一些对 bash
而不是 sh
的引用,或者仍然定义了一个包装器来调用 Python 代码。但是我们为什么要操心这些呢?
我再说一遍,就这样做:
0 3 * * * /home/user/project/env/bin/python /home/user/project/manage.py
documentation 确认:
您不需要特别激活环境;激活只是将虚拟环境的二进制目录添加到您的路径中,以便“python”调用虚拟环境的 Python 解释器,您可以运行已安装的脚本而无需使用它们的完整路径。但是,安装在虚拟环境中的所有脚本都应该可以在不激活它的情况下运行,并自动使用虚拟环境的 Python 运行。
与其使用特定于 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...]
对我来说最好的解决方案是两者
使用 venv bin/ 目录中的 python 二进制文件
设置 python 路径以包含 venv 模块目录。
man python
提到在 $PYTHONPATH
处修改 shell 中的路径或使用 sys.path
在 python 中修改路径
其他答案提到了使用外壳执行此操作的想法。在 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
>>>
我想添加这个,因为我花了一些时间解决这个问题,但在这里没有找到关于 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 二进制文件。
这是一种使 crontab 命令与常规命令非常相似的简单方法(在 Ubuntu 18.04 中测试)。要记住的一些关键注意事项:
您可以使用 .命令而不是源。 (crontab 默认使用 sh,而不是 bash,所以它没有源。)
~ 和 $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
如果您在 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
蟒蛇脚本
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 * * * * - 每分钟执行一次
cd /Workspace/testcron/ - python 脚本的路径
/Workspace/testcron/venvcron/bin/python3 - Virtualenv 路径
Workspace/testcron/testcronwithparam.py - 文件路径
参数 - 参数
我在我的 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 中定义环境变量,也无需修改现有脚本。
我有同样的问题,并花了很多时间解决这个问题。这里的解决方案都没有帮助我,所以我分享了对我有用的东西:
打开一个新文件“pick_name.sh”,在您的项目目录中打开它。在“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
转到 /var/spool/cron/crontabs(或您的 cron 管理文件所在的位置)并打开“根”文件。将这些行添加到 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_ouput”的日志文件。之前不需要创建文件,它会自动创建。
确保将所有路径(我用大写字母写成)替换为您的路径。
您可以更改文件名,如果是这样,请确保在我的说明中更改所有外观以避免错误。
如果要添加另一个 py 文件以由 cron 运行,则需要将其添加到“pick_nam.sh”文件*而不是 cron。只需复制“pick_nam.sh”中的第 2 节行,但不包含“#!/bin/bash”部分。然后,每次 cron 运行“pick_name.sh”时,它都会运行您在其中指定的所有文件。
确保更改后重新启动 cron,它可以为我节省大量调试时间,使用以下命令:
systemctl restart cron
这是一个对我来说效果很好的解决方案。
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 运行它,而不会遇到任何麻烦。
这也适用于 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
~
替换为完整路径? (你可能做到了,只是确保......)