Cron и virtualenv

227

Я пытаюсь запустить команду управления Django из cron. Я использую virtualenv, чтобы оставить свой проект изолированным.

Здесь и в других местах я видел примеры, показывающие выполнение команд управления изнутри virtualenv, например:

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

Однако, хотя системный журнал показывает запись, когда задача должна была начаться, эта задача фактически никогда не запускается (файл журнала для скрипта пуст). Если я запускаю строку вручную из оболочки, она работает как положено.

Единственный способ получить команду для запуска через 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 ничего не сделал. Это работает, так и с шоу.

Джон Скотт
источник
Единственное отличие, которое я вижу, заключается в том, что скрипт будет запускать manage.py с / home / user / project в качестве текущего рабочего каталога. Ваша команда cron будет выполняться с вашим домашним каталогом как cwd. Может быть, файл журнала есть?
Реттопс
На самом деле путь к журналу определен абсолютно, он просто не создается / не добавляется, потому что скрипт не запущен.
Джон Скотт
Быстрое и грязное решение проблем cron - это сбросить вашу среду (в которой ваша команда необъяснимо работает) envи exportвсе это в оболочку bash-скрипта, которую вы вызываете из crontab.
Jberryman

Ответы:

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.
Джон Скотт
Вы заменили ~на полный путь? (Вы , вероятно , сделал, только убедившись , что ...)
АРС
Ах, вы придумали рабочий пример! Я пробовал каждую комбинацию, и активация virtualenv, похоже, не дала никакого эффекта. Я установил свой PYTHONPATH в .bashrc, но он, по-видимому, не используется cron? Обновлю мой вопрос, чтобы выделить ваш ответ.
Джон Скотт
Да, я забыл, что cron работает в очень минимальной среде. Общая рекомендация заключается в написании сценариев bash для настройки среды, в которой будет нужна ваша работа. Вы можете попробовать создать профиль bash напрямую в cron, но это может привести к незначительным ошибкам в зависимости от того, что находится в вашем профиле (возможно, если у вас есть отдельный и минимальный профиль для таких нужд, это было бы хорошо).
АРС
7
Хороший способ проверить это выполнить / bin / sh, а затем попытаться выполнить вашу команду оттуда. По крайней мере, вы будете иметь ту же настройку среды, что и cron.
Дик
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/

DavidWinterbottom
источник
12
Или '.' (точечная команда), которая поддерживается / bin / sh. /path/to/virtualenv/bin/activate
Рид Сандберг
5
Дэвид Уинтерботтом, если это твое настоящее имя, ты мой герой. Я никогда не знал этого о sh vs bash и исходных файлах. Ты пролил свет на мой маленький чувак мира сценариев bash. Спасибо.
Joemurphy
Если у вас есть postactivateфайл, вы должны делатьsource /path/to/virtualenv/bin/activate && source /path/to/virtualenv/bin/postactivate
dspacejs
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

Прелесть этого в том, что вам НЕ нужно менять SHELLпеременную для crontab с shнаbash

Василий Муса
источник
13

Единственный правильный способ запуска заданий python cron при использовании virtualenv - это активировать среду и затем запустить python среды для запуска вашего кода.

Один из способов сделать это - использовать virtualenv activate_thisв вашем скрипте Python, см .: 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
Ivanhoe
источник
1
Мне очень любопытно, есть ли согласие, что это на самом деле единственный правильный путь.
Аарон Шумахер
1
Это, наверное, единственный правильный путь. Но есть и другие способы, которые работают.
Будет
4
Это не «единственный правильный путь». Я успешно выполнил скрипт в virtualenv, просто указав cronjob на двоичный файл python virtualenv, такой как «/ home / user / folder / env / bin / python». Нет необходимости активировать среду вообще.
Canucklesandwich
Если вы используете пользовательский PYTHONPATH в виртуальной среде, env / bin / python вам не подойдет. Вот почему лучше использовать env / bin /
activ
1
это зависит от того, как вы установили PYTHONPATH, и если вы устанавливаете его таким образом, который требует «активации» venv, вы делаете это неправильно
10

Вместо того, чтобы возиться с шебангами, характерными для виртуленва, просто перенеситесь 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...]
joemaller
источник
12
Не очень хорошее решение. Все задачи Python в crontab будут запускаться с двоичным файлом из virtualenv. Создание этого бинарного псевдоглобального питона противоречит самой цели virtualenv.
Виктор Шредер
4

Лучшее решение для меня было для обоих

  • используйте двоичный файл python в каталоге venv bin /
  • установите путь к Python, чтобы включить каталог модулей venv.

man pythonупоминает об изменении пути в оболочке $PYTHONPATHили в python с помощьюsys.path

Другие ответы упоминают идеи сделать это с помощью оболочки. Из 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 / activ"

Спасибо @davidwinterbottom , @ reed-sandberg и @mkb за правильное направление. Принятый ответ на самом деле работает нормально, пока вашему питону не нужно запустить скрипт, который должен запускать другой двоичный файл питона из каталога venv / bin.

Дмитрий
источник
0

Это решение, которое хорошо сработало для меня.

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

Я использую Miniconda с Conda версии 4.7.12 на Ubuntu 18.04.3 LTS.

Я могу поместить вышеупомянутое в сценарий и запустить его через crontab также без каких-либо проблем.

Арун Тундиилл Сасендран
источник
0

скрипт на питоне

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
  • / Рабочая область / testcron / venvcron / bin / python3 - Virtualenv path
  • Рабочая область / testcron / testcronwithparam.py - Путь к файлу
  • параметр - параметр
Рамеш Поннусамы
источник