Cron і virtualenv


227

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

Я бачив приклади тут і в інших місцях, які показують запущені команди управління зсередини virtualenv на зразок:

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

Однак, хоча syslog показує запис, коли завдання повинно було бути запущене, це завдання ніколи насправді не запускається (файл журналу для сценарію порожній). Якщо я запускаю лінію вручну з оболонки, вона працює як очікувалося.

Єдиний спосіб, коли я можу отримати команду для запуску через cron, - це розбити команди і помістити їх у німий сценарій баш-обгортки:

#!/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 нічого не робив. Це працює, так і з шоу.


Я бачу одну різницю в тому, що сценарій буде запускати Manag.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

EDIT: Якщо ваш проект джанго відсутній у 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? Буде оновлено моє запитання, щоб виділити вашу відповідь.
Джон-Скотт

Так, я забув, що крон працює в дуже мінімальних умовах. Загальна рекомендація - писати 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не записує відомості про помилку. Найкраще псевдонімувати корінь, щоб ви отримали електронні листи з будь-якими помилками 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
Рид Сандберг

5
DavidWinterbottom, якщо це твоє справжнє ім’я, ти мій герой. Я ніколи цього не знав про sh vs bash та вихідні файли. Ти засяяв світло моєму маленькому чудовому світовому чуваку. Дякую.
joemurphy

Якщо у вас є postactivateфайл, ви повинні робитиsource /path/to/virtualenv/bin/activate && source /path/to/virtualenv/bin/postactivate
dspacejs

1
Дякую! Для мене це працює, а не прийнята відповідь Джеральда.
Мартін Беккер

1
для чого "корінь"? хтось може пояснити
adnanmuttaleb

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

1
Мені дуже цікаво, чи існує консенсус, що це насправді єдиний правильний спосіб.
Аарон Шумахер

1
Це, мабуть, єдино правильний спосіб. Але є й інші способи, які працюють.
Буде чи

4
Це не єдиний правильний спосіб. Я успішно виконав сценарій у virtualenv, просто вказавши cronjob на бінарний пітон virtualenv, такий як '/ home / user / folder / env / bin / python'. Не потрібно активувати середовище взагалі.
Canucklesandwich

Якщо ви використовуєте користувацький PYTHONPATH у віртуальному середовищі, env / bin / python не працюватиме для вас. Тому краще використовувати env / bin / activate
varela

1
це залежить від того, як ви встановите PYTHONPATH і якщо ви встановите його таким чином, що вимагає "активації" venv, ви робите це неправильно

10

Замість того, щоб розмовляти навколо специфічних для virtualenv шебангів, просто переходьте 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...]

12
Не вдале рішення. Кожні завдання пітона в crontab потім виконувались бинарними файлами від virtualenv. Перетворення цього бінарного псевдоглобального пітона суперечить самій цілі віртуаленв.
Віктор Шредер

4

Найкращим рішенням для мене було обидва

  • використовуйте бінар пітона в каталозі venv bin / directory
  • встановіть шлях 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 / activate"

Дякуємо @davidwinterbottom , @ reed -sandberg та @mkb за те, що дали правильний напрямок. Прийнята відповідь насправді працює добре, поки вашому python не потрібно запустити сценарій, який повинен запустити ще один бінарний файл python з каталогу 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

сценарій 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 * * * * - Виконайте кожну ковану
  • cd / Робоча область / testcron / - Шлях сценарію python
  • / Робоча область / testcron / venvcron / bin / python3 - Virtualenv шлях
  • Робоча область / testcron / testcronwithparam.py - Шлях файлу
  • param - параметр
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.