Cron y virtualenv


Estoy tratando de ejecutar un comando de administración de Django desde cron. Estoy usando virtualenv para mantener mi proyecto aislado.

He visto ejemplos aquí y en otros lugares que muestran la ejecución de comandos de administración desde dentro de virtualenv como:

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

Sin embargo, aunque syslog muestra una entrada cuando la tarea debería haber comenzado, esta tarea nunca se ejecuta (el archivo de registro del script está vacío). Si corro la línea manualmente desde el shell, funciona como se esperaba.

La única manera actualmente puede obtener el comando para ejecutarse a través de cron, es romper los comandos y ponerlos en un script de envoltura bash tonto:

#!/bin/sh
source /home/user/project/env/bin/activate
cd /home/user/project/
./manage.py command arg

EDITAR:

A Ars se le ocurrió una combinación de comandos:

0 3 * * * cd /home/user/project && /home/user/project/env/bin/python /home/user/project/manage.py command arg

Al menos en mi caso, invocar el script activate para virtualenv no hizo nada. Esto funciona, así que con el programa.

Author: Francisco Couzo, 2010-07-20

7 answers

Debería poder hacer esto usando el python en su entorno virtual:

/home/my/virtual/bin/python /home/my/project/manage.py command arg

EDITAR: Si tu proyecto django no está en PYTHONPATH, entonces necesitarás cambiar al directorio correcto:

cd /home/my/project && /home/my/virtual/bin/python ...

También puede intentar registrar el fallo desde cron:

cd /home/my/project && /home/my/virtual/bin/python /home/my/project/manage.py > /tmp/cronlog.txt 2>&1

Otra cosa a intentar es hacer el mismo cambio en su script manage.py en la parte superior:

#!/home/my/virtual/bin/python
 188
Author: ars,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-09 22:27:32

Ejecutar source desde un cronfile no funcionará ya que cron usa /bin/sh como su shell predeterminado, que no soporta source. Necesita establecer la variable de entorno SHELL como /bin/bash:

SHELL=/bin/bash
*/10 * * * * root source /path/to/virtualenv/bin/activate && /path/to/build/manage.py some_command > /dev/null

Es difícil detectar por qué esto falla ya que /var/log/syslog no registra los detalles del error. Lo mejor es que te pongas un alias en root para que te envíen un correo electrónico con cualquier error de cron. Simplemente agrégate a /etc/aliases y ejecuta sendmail -bi.

Más información aqui: http://codeinthehole.com/archives/43-Running-django-cronjobs-within-a-virtualenv.html

 73
Author: DavidWinterbottom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-11 19:33:35

En lugar de perder el tiempo con shebangs específicos de virtualenv, simplemente anteponga PATH en el crontab.

Desde un virtualenv activado, ejecute estos tres comandos y los scripts de python deberían funcionar:

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

La primera línea del crontab debería verse así:

PATH=/home/me/virtualenv/bin:/usr/bin:/bin:  # [etc...]
 11
Author: joemaller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-12 04:42:01

La única forma correcta de ejecutar trabajos cron de python cuando se utiliza un virtualenv es activar el entorno y luego ejecutar python del entorno para ejecutar su código.

Una forma de hacer esto es usar el activate_this de virtualenv en su script python, vea: http://virtualenv.readthedocs.org/en/latest/userguide.html#using-virtualenv-without-bin-python

Otra solución está haciendo eco del comando completo, incluyendo la activación del entorno y la tubería en /bin/bash. Considere esto para su /etc/crontab:

***** root echo 'source /env/bin/activate; python /your/script' | /bin/bash
 8
Author: Ivanhoe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-27 23:34:44

No busques más:

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

Enfoque genérico:

* * * * * /usr/bin/env bash -c 'YOUR_COMMAND_HERE' > /dev/null 2>&1

La belleza de esto es que NO necesita cambiar la variable SHELL para crontab de sh a bash

 3
Author: Basil Musa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-27 21:32:19

La mejor solución para mí fue tanto

  • utilice el binario python en el directorio venv bin/
  • establecer la ruta de python para incluir el directorio de módulos venv.

man python menciona modificar la ruta en shell en $PYTHONPATH o en python con sys.path

Otras respuestas mencionan ideas para hacer esto usando el shell. Desde python, agregar las siguientes líneas a mi script me permite ejecutarlo con éxito directamente desde cron.

import sys
sys.path.insert(0,'/path/to/venv/lib/python3.3/site-packages');

Así es como se ve en un sesión interactiva --

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
>>>
 2
Author: here,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-25 08:00:09

Me gustaría agregar esto porque pasé algún tiempo resolviendo el problema y no encontré una respuesta aquí para la combinación de uso de variables en cron y virtualenv. Así que tal vez ayude a alguien.

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

No funcionó bien cuando se configuró como

DIR_SMTH="cd /smth && . venv / bin / activate "

Gracias @davidwinterbottom, @reed-sandberg y @mkb para dar la dirección correcta. La respuesta aceptada realmente funciona bien hasta que su python necesita ejecutar un script que tiene que ejecutar otro binario python desde el directorio venv/bin.

 0
Author: Dmitriy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-08 15:26:50