Cron und virtualenv

227

Ich versuche, einen Django-Verwaltungsbefehl von cron aus auszuführen. Ich verwende virtualenv, um mein Projekt in einer Sandbox zu halten.

Ich habe hier und anderswo Beispiele gesehen, die das Ausführen von Verwaltungsbefehlen innerhalb von virtualenv zeigen, wie:

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

Obwohl syslog einen Eintrag anzeigt, wann die Aufgabe hätte gestartet werden sollen, wird diese Aufgabe nie ausgeführt (die Protokolldatei für das Skript ist leer). Wenn ich die Zeile manuell über die Shell ausführe, funktioniert sie wie erwartet.

Die einzige Möglichkeit, den Befehl derzeit über cron auszuführen, besteht darin, die Befehle aufzuteilen und in ein dummes Bash-Wrapper-Skript zu schreiben:

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

BEARBEITEN:

ars hat eine funktionierende Kombination von Befehlen entwickelt:

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

Zumindest in meinem Fall hat das Aufrufen des Aktivierungsskripts für die virtuelle Umgebung nichts bewirkt. Das funktioniert so weiter mit der Show.

John-Scott
quelle
Ein Unterschied, den ich sehe, ist, dass das Skript manage.py mit / home / user / project als aktuellem Arbeitsverzeichnis ausführt. Ihr Befehl cron wird mit Ihrem Ausgangsverzeichnis als cwd ausgeführt. Vielleicht ist die Protokolldatei da?
rettops
Tatsächlich ist der Protokollpfad absolut definiert, er wird einfach nicht erstellt / angehängt, da das Skript nicht ausgeführt wird.
John-Scott
Eine schnelle und schmutzige Lösung für Cron-Probleme besteht darin, Ihre Umgebung (in der Ihr Befehl unerklärlicherweise funktioniert) mit envund exportallen in einem Bash-Skript-Wrapper zu sichern, den Sie von der Crontab aus aufrufen.
Jberryman

Antworten:

250

Sie sollten dazu in der Lage sein, indem Sie pythonin Ihrer virtuellen Umgebung Folgendes verwenden:

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

BEARBEITEN: Wenn sich Ihr Django-Projekt nicht im PYTHONPATH befindet, müssen Sie in das richtige Verzeichnis wechseln:

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

Sie können auch versuchen, den Fehler von cron zu protokollieren:

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

Sie können auch versuchen, die gleiche Änderung in Ihrem manage.pySkript ganz oben vorzunehmen :

#!/home/my/virtual/bin/python
ars
quelle
1
Das geht auch nicht. Ich habe vergessen, das in meine Liste der Dinge aufzunehmen, die nicht funktionieren. Ja, ich kann diesen Befehl manuell in der Shell ausführen, aber er funktioniert nicht von cron aus.
John-Scott
Haben Sie durch ~den vollständigen Pfad ersetzt? (Sie haben es wahrscheinlich getan, nur um sicherzugehen ...)
Ars
Ah, Sie haben ein funktionierendes Beispiel gefunden! Ich habe jede Kombination ausprobiert und die Aktivierung der virtuellen Umgebung scheint keinerlei Auswirkungen zu haben. Ich setze meinen PYTHONPATH auf .bashrc, aber dies wird anscheinend nicht von cron verwendet? Aktualisiert meine Frage, um Ihre Antwort hervorzuheben.
John-Scott
Ja, ich hatte vergessen, dass Cron unter einer sehr minimalen Umgebung läuft. Die allgemeine Empfehlung lautet, Bash-Skripte zu schreiben, um die Umgebung einzurichten, die Ihr Job benötigt. Sie könnten versuchen, das Bash-Profil direkt in Cron zu beziehen, dies kann jedoch zu subtilen Fehlern führen, je nachdem, was in Ihrem Profil enthalten ist (möglicherweise ist es in Ordnung, wenn Sie ein separates und minimales Profil für solche Anforderungen haben).
Ars
7
Eine gute Möglichkeit zum Testen besteht darin, / bin / sh auszuführen und dann zu versuchen, Ihren Befehl von dort aus auszuführen. Zumindest haben Sie die gleiche Umgebung wie cron eingerichtet.
Dick
98

Das Ausführen sourcevon einer Cronfile funktioniert nicht so, wie Cron es /bin/shals Standard-Shell verwendet, was nicht unterstützt wird source. Sie müssen die Umgebungsvariable SHELL wie folgt festlegen /bin/bash:

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

Es ist schwierig zu erkennen, warum dies fehlschlägt, da /var/log/syslogdie Fehlerdetails nicht protokolliert werden. Am besten aliasen Sie sich als root, damit Sie per E-Mail über Cron-Fehler informiert werden. Füge dich einfach hinzu /etc/aliasesund renne sendmail -bi.

Weitere Informationen hier: http://codeinthehole.com/archives/43-Running-django-cronjobs-within-a-virtualenv.html

Der obige Link wird geändert in: https://codeinthehole.com/tips/running-django-cronjobs-within-a-virtualenv/

DavidWinterbottom
quelle
12
Oder '.' (Punkt Befehl), der von / bin / sh. /path/to/virtualenv/bin/activate
Reed Sandberg
5
DavidWinterbottom, wenn das dein richtiger Name ist, bist du mein Held. Ich wusste das nie über sh vs bash und Quelldateien. Du hast ein Licht in meinen kleinen Bash-Scripting-Weltkumpel geworfen. Vielen Dank.
Joemurphy
Wenn Sie eine postactivateDatei haben, sollten Sie tunsource /path/to/virtualenv/bin/activate && source /path/to/virtualenv/bin/postactivate
dspacejs
1
Vielen Dank! Für mich funktioniert dies eher als die akzeptierte Antwort von Gerald.
Martin Becker
1
Wofür ist "Wurzel"? kann jemand erklären
adnanmuttaleb
19

Suchen Sie nicht weiter:

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

Generischer Ansatz:

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

Die Schönheit über das , was Sie tun müssen , um die Änderung SHELLfür crontab Variable aus shzubash

Basilikum Musa
quelle
13

Die einzig richtige Möglichkeit, Python-Cron-Jobs auszuführen, wenn Sie eine virtuelle Umgebung verwenden, besteht darin, die Umgebung zu aktivieren und dann die Python der Umgebung auszuführen, um Ihren Code auszuführen.

Eine Möglichkeit, dies zu tun, besteht darin, virtualenvs activate_thisin Ihrem Python-Skript zu verwenden, siehe: http://virtualenv.readthedocs.org/en/latest/userguide.html#using-virtualenv-without-bin-python

Eine andere Lösung besteht darin, den vollständigen Befehl zu wiederholen, einschließlich der Aktivierung und Weiterleitung der Umgebung /bin/bash. Betrachten Sie dies für Ihre /etc/crontab:

***** root echo 'source /env/bin/activate; python /your/script' | /bin/bash
Ivanhoe
quelle
1
Ich bin sehr gespannt, ob Konsens darüber besteht, dass dies tatsächlich der einzig richtige Weg ist.
Aaron Schumacher
1
Dies ist wahrscheinlich der einzig richtige Weg. Es gibt aber auch andere Möglichkeiten, die funktionieren.
Will
4
Dies ist nicht "der einzig richtige Weg". Ich habe ein Skript in einer virtuellen Umgebung erfolgreich ausgeführt, indem ich den Cronjob einfach auf die Python-Binärdatei der virtuellen Umgebung verwiesen habe, z. B. '/ home / user / folder / env / bin / python'. Sie müssen die Umgebung überhaupt nicht aktivieren.
Canucklesandwich
Wenn Sie benutzerdefiniertes PYTHONPATH in einer virtuellen Umgebung verwenden, funktioniert env / bin / python nicht für Sie. Deshalb ist die Verwendung von env / bin /
enable
1
Es hängt davon ab, wie Sie den PYTHONPATH einstellen. Wenn Sie ihn so einstellen, dass das Venv "aktiviert" werden muss, machen Sie es falsch
10

Anstatt mit virtualenv-spezifischen Shebangs herumzuspielen, stellen Sie sich einfach PATHauf die Crontab.

Führen Sie auf einer aktivierten virtuellen Umgebung diese drei Befehle aus, und Python-Skripte sollten einfach funktionieren:

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

Die erste Zeile des Crontab sollte nun folgendermaßen aussehen:

PATH=/home/me/virtualenv/bin:/usr/bin:/bin:  # [etc...]
Joemaller
quelle
12
Keine gute Lösung. Alle Python-Aufgaben in der Crontab würden dann mit der Binärdatei von der virtuellen Umgebung ausgeführt. Diese Binärdatei zu einer pseudo-globalen Python zu machen, widerspricht dem eigentlichen Zweck von virtualenv.
Victor Schröder
4

Die beste Lösung für mich war für beide

  • Verwenden Sie die Python-Binärdatei im Verzeichnis venv bin /
  • Stellen Sie den Python-Pfad so ein, dass er das Verzeichnis der venv-Module enthält.

man pythonerwähnt das Ändern des Pfades in der Shell bei $PYTHONPATHoder in Python mitsys.path

Andere Antworten erwähnen Ideen, um dies unter Verwendung der Shell zu tun. Wenn ich von Python aus die folgenden Zeilen zu meinem Skript hinzufüge, kann ich es erfolgreich direkt von cron aus ausführen.

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

So sieht es in einer interaktiven Sitzung aus:

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
>>>
Hier
quelle
4

Ich möchte dies hinzufügen, da ich einige Zeit damit verbracht habe, das Problem zu lösen, und hier keine Antwort für die Kombination der Verwendung von Variablen in cron und virtualenv gefunden habe. Vielleicht hilft es jemandem.

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

Es hat nicht gut funktioniert, als es wie konfiguriert wurde

DIR_SMTH = "cd / smth &&. Venv / bin / enabled"

Vielen Dank an @davidwinterbottom , @ reed-sandberg und @mkb für die richtige Richtung. Die akzeptierte Antwort funktioniert tatsächlich einwandfrei, bis Ihr Python ein Skript ausführen muss, das eine andere Python-Binärdatei aus dem Verzeichnis venv / bin ausführen muss.

Dmitriy
quelle
0

Dies ist eine Lösung, die für mich gut funktioniert hat.

source /root/miniconda3/etc/profile.d/conda.sh && \
conda activate <your_env> && \
python <your_application> &

Ich verwende Miniconda mit Conda Version 4.7.12 auf einem Ubuntu 18.04.3 LTS.

Ich kann das Obige in ein Skript einfügen und es auch problemlos über crontab ausführen.

Arun Thundyill Saseendran
quelle
0

Python-Skript

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

 */1 * * * *  cd /Workspace/testcron/ && /Workspace/testcron/venvcron/bin/python3  /Workspace/testcron/testcronwithparam.py param  

Im obigen Befehl

  • * / 1 * * * * - Jede Minute ausführen
  • cd / Workspace / testcron / - Pfad des Python-Skripts
  • / Workspace / testcron / venvcron / bin / python3 - Virtualenv-Pfad
  • Workspace / testcron / testcronwithparam.py - Dateipfad
  • param - parameter
Ramesh Ponnusamy
quelle