2010-07-20 25 views
161

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

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

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

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

La única forma en que actualmente puedo conseguir el comando para ejecutar a través de cron, es romper los comandos y los puso en una muda escritura del golpe envoltorio:

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

EDIT:

ars subió con una combinación de trabajo de comandos:

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

por lo menos en mi caso, la invocación de la secuencia de comandos de activación para el virtualenv no hicieron nada. Esto funciona, etc. con el espectáculo.

+0

Una diferencia que veo es que el script se ejecutará con manage.py/home/usuario/proyecto como el directorio de trabajo actual. Su comando cron se ejecutará con su directorio de inicio como cwd. Tal vez el archivo de registro está allí? – rettops

+0

En realidad, la ruta del registro se define de manera absoluta, simplemente no se crea/no se agrega porque el script no se está ejecutando. –

+0

Una solución rápida y sucia a los problemas de cron consiste en volcar su entorno (en el cual su comando inexplicablemente está funcionando) con 'env' y' export' en un contenedor de script bash que usted llama desde el crontab. – jberryman

Respuesta

170

Usted debe ser capaz de hacer esto mediante el uso de la python en su entorno virtual:

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

EDIT: Si su proyecto Django no está en la PYTHONPATH, entonces tendrá que cambiar a la derecha directorio:

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

también puede tratar de registrar el fallo de 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 la secuencia de comandos manage.py en la parte superior:

#!/home/my/virtual/bin/python 
+1

Eso tampoco funciona. Olvidé poner eso en mi lista de cosas que no funcionan. Sí, puedo ejecutar ese comando manualmente en el shell pero no funciona desde cron. –

+0

¿Reemplazó '~' con la ruta completa? (Probablemente lo hiciste, solo asegúrate de ...) – ars

+0

¡Ah, has creado un ejemplo de trabajo! He intentado con cada combinación y la activación del virtualenv parece no tener ningún efecto en absoluto. Sí configuro mi PYTHONPATH en .bashrc, pero aparentemente, cron no lo usa? Actualizaré mi pregunta para resaltar su respuesta. –

64

Correr source de un cronfile no va a funcionar como cron utiliza /bin/sh como su shell por defecto, que no soporta source. Es necesario establecer la variable de entorno SHELL ser /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 de detectar por qué esto no funciona como /var/log/syslog no registra los detalles del error. Lo mejor es alias a la raíz para recibir un correo electrónico con cualquier error cron. Simplemente agréguese a /etc/aliases y ejecute sendmail -bi.

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

+9

O '.' (comando de punto), que es compatible con/bin/sh './ruta/a/virtualenv/bin/activate' –

+4

DavidWinterbottom, si ese es tu nombre real, eres mi héroe. Nunca supe eso sobre los archivos sh vs bash y fuente. Has iluminado a mi pequeño amigo del mundo de scripts de bash. Gracias. – joemurphy

+0

Si tiene un archivo 'postactivate', debe hacer' source/path/to/virtualenv/bin/activate && source/path/to/virtualenv/bin/postactivate' – dspacejs

11

lugar de al rededor del shebangs-virtualenv específica, simplemente escriba PATH en el crontab.

Desde un virtualenv activado, ejecute estos tres comandos y scripts de Python simplemente deben trabajar:

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

primera línea del crontab ahora debería tener este aspecto:

PATH=/home/me/virtualenv/bin:/usr/bin:/bin: # [etc...] 
+1

No es una buena solución. Todas las tareas de python en el crontab se ejecutarían con el binario del virtualenv. Hacer que el binario sea un _pseudo-global_ python va en contra del verdadero propósito de virtualenv. –

7

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

Una forma de hacerlo es utilizar de virtualenv activate_this en su script en Python, consulte: http://virtualenv.readthedocs.org/en/latest/userguide.html#using-virtualenv-without-bin-python

Otra solución se hace eco el comando completo que incluye activar el medio ambiente y la tubería en /bin/bash. Considere esto para su /etc/crontab:

***** root echo 'source /env/bin/activate; python /your/script' | /bin/bash 
+0

Tengo mucha curiosidad en cuanto a si hay consenso de que esta es, de hecho, la única forma correcta. –

+0

Esta es probablemente la única forma correcta. Pero hay otras formas en que funciona. – Will

+2

Esta no es "la única forma correcta". He ejecutado correctamente un script en virtualenv simplemente apuntando el cronjob al virtualenv's python binary, como '/ home/user/folder/env/bin/python'. No es necesario activar el entorno en absoluto. – tracicot

1

La mejor solución para mí era tanto

  • utilizar el binario pitón en la papelera Venv/directorio
  • establecer la ruta de pitón para incluir los módulos Venv directorio.

man python menciones modificar la ruta en la cáscara en $PYTHONPATH o en Python con sys.path

Otras respuestas mencionar ideas para hacer esto utilizando la cáscara. 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 una 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 
>>>