2010-07-20 12 views
161

Sto provando a eseguire un comando di gestione Django da cron. Sto usando virtualenv per mantenere il mio progetto in modalità sandbox.Cron e virtualenv

Ho visto esempi qui e altrove che mostrano l'esecuzione di comandi di gestione dall'interno virtualenv di simile:

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

Tuttavia, anche se syslog mostra una voce quando il compito avrebbe dovuto cominciare, questo compito viene eseguito in realtà mai (la il file di registro per lo script è vuoto). Se eseguo la linea manualmente dalla shell, funziona come previsto.

L'unico modo che posso attualmente ottenere il comando da eseguire tramite cron, è quello di rompere i comandi su e metterli in un muto script bash avvolgitore:

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

EDIT:

ars si avvicinò con una combinazione di lavoro di comandi:

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

almeno nel mio caso, invocando lo script di attivazione per il virtualenv non ha fatto nulla. Funziona così, così via con lo spettacolo.

+0

Una differenza che vedo è che lo script verrà eseguito manage.py con/home/utente/progetto come directory di lavoro corrente. Il tuo comando cron verrebbe eseguito con la tua home directory come cwd. Forse il file di registro è lì? – rettops

+0

In realtà il percorso del log è definito in modo assoluto, semplicemente non viene creato/aggiunto perché lo script non è in esecuzione. –

+0

Una soluzione rapida e sporca ai problemi di cron è scaricare l'ambiente (in cui il comando funziona inspiegabilmente) con 'env' e 'esportarli' tutti in un wrapper di script bash che chiamate da crontab. – jberryman

risposta

170

Si dovrebbe essere in grado di farlo utilizzando il python nel vostro ambiente virtuale:

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

EDIT: Se il progetto Django non è nel PYTHONPATH, allora avrete bisogno di passare a destra directory:

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

È anche provare a registrare il fallimento da cron:

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

Un'altra cosa da provare è quello di rendere lo stesso cambiamento nello script manage.py al vertice:

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

Anche questo non funziona. Ho dimenticato di inserirlo nella mia lista di cose che non funzionano. Sì, posso eseguire quel comando manualmente nella shell ma non funziona da cron. –

+0

Hai sostituito '~' con il percorso completo? (Probabilmente lo hai fatto, solo assicurandoti ...) – ars

+0

Ah, hai trovato un esempio funzionante! Ho provato su ogni combinazione e l'attivazione del virtualenv sembra non avere alcun effetto. Ho impostato il mio PYTHONPATH in .bashrc ma questo apparentemente non è usato da cron? Aggiornerà la mia domanda per evidenziare la tua risposta. –

64

Esecuzione source da un cronfile non funzionerà come cron usa /bin/sh come shell di default, che non supporta source. È necessario impostare la variabile d'ambiente SHELL essere /bin/bash:

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

E 'difficile da individuare il motivo per cui questo viene a mancare, come /var/log/syslog non registra i dettagli dell'errore. Meglio fare l'alias di te stesso per root in modo da ricevere email con eventuali errori cron. È sufficiente aggiungere te stesso a /etc/aliases ed eseguire sendmail -bi.

Maggiori informazioni qui: http://codeinthehole.com/archives/43-Running-django-cronjobs-within-a-virtualenv.html

+9

Oppure '.' (comando punto), che è supportato da/bin/sh './percorso/per/virtualenv/bin/activate' –

+4

DavidWinterbottom, se questo è il tuo vero nome, sei il mio eroe. Non l'ho mai saputo di sh vs bash e dei file sorgente. Hai illuminato una luce nel mio piccolo amico del mondo di scripting bash. Grazie. – joemurphy

+0

Se si dispone di un file 'postactivate', si dovrebbe fare' source/path/to/virtualenv/bin/activate && source/path/to/virtualenv/bin/postactivate' – dspacejs

11

Invece di gingillarsi con SheBangs specifici virtualenv, basta anteporre PATH sul crontab.

Dal virtualenv attivato, eseguire questi tre comandi e script Python dovrebbe funzionare:

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

La prima riga del crontab dovrebbe apparire così:

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

Non è una buona soluzione. Ogni task python nel crontab sarebbe quindi eseguito con il binario dal virtualenv. Rendendo quel binario un python _pseudo-global_ va contro lo scopo stesso di virtualenv. –

7

L'unico modo corretto di correre python cron jobs quando si utilizza virtualenv è per attivare l'ambiente e quindi eseguire python dell'ambiente per eseguire il codice.

Un modo per farlo è usare di virtualenv activate_this nello script python, vedi: http://virtualenv.readthedocs.org/en/latest/userguide.html#using-virtualenv-without-bin-python

Un'altra soluzione è eco il comando completo che comprende l'attivazione l'ambiente e tubazioni in /bin/bash. Considerate questo per il vostro /etc/crontab:

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

Sono molto curioso di sapere se c'è consenso sul fatto che questo sia in realtà l'unico modo corretto. –

+0

Questo è probabilmente l'unico modo corretto. Ma ci sono altri modi in cui funziona. – Will

+2

Questo non è "l'unico modo corretto". Ho eseguito con successo uno script in un virtualenv semplicemente puntando il cronjob sul python di virtualenv, come '/ home/utente/cartella/env/bin/python'. Non è necessario attivare l'ambiente in alcun modo. – tracicot

1

La soluzione migliore per me era sia

  • utilizzare il binario pitone nel venv bin/directory
  • impostare il percorso pitone per includere i moduli venv directory.

man python menzioni modificando il percorso in guscio a $PYTHONPATH o in pitone con sys.path

altre risposte menzione idee per fare questo usando la shell. Da Python, aggiungere le seguenti righe al mio script mi ​​consente di eseguirlo correttamente da cron.

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

Ecco come appare in una sessione interattiva -

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