Cron et virtualenv
j'essaie d'exécuter un ordre de gestion de Django de cron. J'utilise virtualenv pour garder mon projet dans un bac à sable.
j'ai vu des exemples ici et ailleurs qui montrent comment exécuter des commandes de gestion à partir de virtualenv comme:
0 3 * * * source /home/user/project/env/bin/activate && /home/user/project/manage.py command arg
cependant, même si syslog affiche une entrée lorsque la tâche aurait dû commencer, cette tâche ne s'exécute jamais (le fichier journal du script est vide). Si j'exécute la ligne manuellement à partir de la coquille, il fonctionne comme prévu.
la seule façon dont je peux actuellement faire tourner la commande via cron, est de casser les commandes et de les mettre dans un script d'enveloppement de bash muet:
#!/bin/sh
source /home/user/project/env/bin/activate
cd /home/user/project/
./manage.py command arg
EDIT:
ars est venu avec une combinaison de commandes:
0 3 * * * cd /home/user/project && /home/user/project/env/bin/python /home/user/project/manage.py command arg
au moins dans mon cas, invoquer le script d'activation pour le virtualenv n'a rien fait. Cela fonctionne, donc le spectacle.
7 réponses
vous devriez pouvoir le faire en utilisant le python
dans votre environnement virtuel:
/home/my/virtual/bin/python /home/my/project/manage.py command arg
éditer: si votre projet django n'est pas dans le PYTHONPATH, alors vous aurez besoin de passer au répertoire de droite:
cd /home/my/project && /home/my/virtual/bin/python ...
vous pouvez également essayer d'enregistrer l'échec de cron:
cd /home/my/project && /home/my/virtual/bin/python /home/my/project/manage.py > /tmp/cronlog.txt 2>&1
une autre chose à essayer est de faire le même changement dans votre script manage.py
en haut:
#!/home/my/virtual/bin/python
exécuter source
à partir d'un fichier Cron ne fonctionnera pas car cron utilise /bin/sh
comme shell par défaut, qui ne supporte pas source
. Vous devez définir la variable D'environnement SHELL comme étant /bin/bash
:
SHELL=/bin/bash
*/10 * * * * root source /path/to/virtualenv/bin/activate && /path/to/build/manage.py some_command > /dev/null
il est difficile de comprendre pourquoi cela ne fonctionne pas, car /var/log/syslog
n'enregistre pas les détails de l'erreur. Il est préférable de vous identifier vous-même pour root afin que vous obteniez par e-mail toutes les erreurs cron. Ajoutez simplement /etc/aliases
et lancez sendmail -bi
.
plus d'informations ici: http://codeinthehole.com/archives/43-Running-django-cronjobs-within-a-virtualenv.html
plutôt que de se moquer de shebangs virtualenv spécifiques, il suffit de prepend PATH
sur le crontab.
à partir d'un virtualenv activé, exécutez ces trois commandes et les scripts python devraient simplement fonctionner:
$ echo "PATH=$PATH" > myserver.cron
$ crontab -l >> myserver.cron
$ crontab myserver.cron
la première ligne du crontab devrait maintenant ressembler à ceci:
PATH=/home/me/virtualenv/bin:/usr/bin:/bin: # [etc...]
la seule façon correcte d'exécuter des tâches en cron python lorsqu'on utilise un virtualenv est d'activer l'environnement et ensuite d'exécuter le code python de l'environnement.
une façon de le faire est d'utiliser le activate_this
de virtualenv dans votre script python, voir: http://virtualenv.readthedocs.org/en/latest/userguide.html#using-virtualenv-without-bin-python
une autre solution fait écho à la commande complète incluant activation de l'environnement et canalisation dans /bin/bash
. Considérez ceci pour votre /etc/crontab
:
***** root echo 'source /env/bin/activate; python /your/script' | /bin/bash
Ne cherchez pas plus loin:
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
approche Générique:
* * * * * /usr/bin/env bash -c 'YOUR_COMMAND_HERE' > /dev/null 2>&1
La beauté à ce sujet est que vous N'avez PAS besoin de changer le SHELL
variable pour la crontab de sh
à bash
la meilleure solution pour moi était à la fois
- utiliser le binaire python dans le bin/ répertoire venv
- définit le chemin du python pour inclure le répertoire des modules venv.
man python
mentions modifiant le chemin dans shell à $PYTHONPATH
ou en python avec sys.path
D'autres réponses mentionnent des idées pour faire cela en utilisant le shell. De python, en ajoutant les lignes suivantes à mon script me permet de l'exécuter directement depuis cron.
import sys
sys.path.insert(0,'/path/to/venv/lib/python3.3/site-packages');
voici à quoi ça ressemble dans une session interactive --
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
>>>
j'aimerais ajouter ceci parce que j'ai passé du temps à résoudre le problème et je n'ai pas trouvé de réponse ici pour la combinaison des variables usage dans cron et virtualenv. Alors peut-être que ça aidera quelqu'un.
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
cela ne fonctionnait pas bien quand il était configuré comme
DIR_SMTH= " cd / smth && . venv / bin / activate "
Merci @davidwinterbottom , @reed-sandberg et @mkb pour avoir donné la bonne direction. La réponse acceptée fonctionne en fait très bien jusqu'à ce que votre python ait besoin d'exécuter un script qui doit exécuter un autre binaire python du répertoire venv/bin.