Cron dan virtualenv


227

Saya mencoba menjalankan perintah manajemen Django dari cron. Saya menggunakan virtualenv untuk menjaga proyek saya di-sandbox.

Saya telah melihat contoh di sini dan di tempat lain yang menunjukkan menjalankan perintah manajemen dari dalam virtualenv seperti:

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

Namun, meskipun syslog menunjukkan entri ketika tugas seharusnya dimulai, tugas ini tidak pernah benar-benar berjalan (file log untuk skrip kosong). Jika saya menjalankan baris secara manual dari shell, itu berfungsi seperti yang diharapkan.

Satu-satunya cara saat ini saya bisa mendapatkan perintah untuk dijalankan melalui cron, adalah dengan memecah perintah dan menempatkannya dalam skrip wrapper bash bodoh:

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

EDIT:

ars datang dengan kombinasi perintah yang berfungsi:

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

Setidaknya dalam kasus saya, menjalankan skrip aktivasi untuk virtualenv tidak melakukan apa-apa. Ini berfungsi, begitu seterusnya dengan pertunjukan.


Satu perbedaan yang saya lihat adalah script akan menjalankan manage.py dengan / home / user / project sebagai direktori kerja saat ini. Perintah cron Anda akan dijalankan dengan direktori home Anda sebagai cwd. Mungkin file log itu ada?
rettop

Sebenarnya path log didefinisikan secara absolut, itu hanya tidak dibuat / ditambahkan ke karena skrip tidak berjalan.
John-Scott

Solusi cepat dan kotor untuk masalah cron adalah dengan membuang lingkungan Anda (di mana perintah Anda tidak bisa dijelaskan) dengan envdan exportsemuanya dalam bungkus skrip bash yang Anda panggil dari crontab.
jberryman

Jawaban:


250

Anda harus dapat melakukan ini dengan menggunakan pythondi lingkungan virtual Anda:

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

EDIT: Jika proyek Django Anda tidak ada di PYTHONPATH, maka Anda harus beralih ke direktori yang benar:

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

Anda juga dapat mencoba mencatat kegagalan dari cron:

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

Hal lain yang harus dicoba adalah membuat perubahan yang sama pada manage.pyskrip Anda di bagian paling atas:

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

1
Itu juga tidak berhasil. Lupa memasukkannya ke dalam daftar hal-hal yang tidak berfungsi. Ya, saya bisa menjalankan perintah itu secara manual di shell tetapi tidak bekerja dari cron.
John-Scott

Apakah Anda mengganti ~dengan path lengkap? (Anda mungkin melakukannya, hanya memastikan ...)
ars

Ah, Anda menemukan contoh yang bagus! Saya sudah mencoba setiap kombinasi dan mengaktifkan virtualenv tampaknya tidak berpengaruh apa pun. Saya mengatur PYTHONPATH saya di .bashrc tapi ini sepertinya tidak digunakan oleh cron? Akan memperbarui pertanyaan saya untuk menyoroti jawaban Anda.
John-Scott

Ya, saya lupa bahwa cron beroperasi di lingkungan yang sangat minim. Rekomendasi umum adalah untuk menulis skrip bash untuk mengatur lingkungan apa pun yang dibutuhkan pekerjaan Anda. Anda dapat mencoba sumber profil bash langsung di cron, tetapi ini dapat menyebabkan bug halus tergantung pada apa yang ada di profil Anda (mungkin jika Anda memiliki profil terpisah dan minimal untuk kebutuhan seperti itu, itu akan baik-baik saja).
ars

7
Cara yang baik untuk menguji adalah dengan mengeksekusi / bin / sh, dan kemudian coba jalankan perintah Anda dari sana. Setidaknya Anda akan memiliki pengaturan lingkungan yang sama dengan cron.
Dick

98

Menjalankan sourcedari cronfile tidak akan berfungsi sebagaimana cron menggunakan /bin/shsebagai shell default, yang tidak mendukung source. Anda perlu mengatur variabel lingkungan SHELL menjadi /bin/bash:

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

Sulit untuk /var/log/syslogmengetahui mengapa ini gagal karena tidak mencatat rincian kesalahan. Terbaik untuk alias diri Anda untuk melakukan rooting sehingga Anda dapat diemail dengan kesalahan cron. Cukup tambahkan diri Anda /etc/aliasesdan jalankan sendmail -bi.

Info lebih lanjut di sini: http://codeinthehole.com/archives/43-Running-django-cronjobs-within-a-virtualenv.html

tautan di atas diubah menjadi: https://codeinthehole.com/tips/running-django-cronjobs-within-a-virtualenv/


12
Atau '.' (titik perintah), yang didukung oleh / bin / sh. /path/to/virtualenv/bin/activate
Reed Sandberg

5
DavidWinterbottom, jika itu nama asli Anda, Anda adalah pahlawan saya. Saya tidak pernah tahu tentang sh vs bash dan file sumber. Anda telah menyinari dude kecil dunia bash-scripting saya. Terima kasih.
joemurphy

Jika Anda memiliki postactivatefile, Anda harus melakukansource /path/to/virtualenv/bin/activate && source /path/to/virtualenv/bin/postactivate
dspacejs

1
Terima kasih! Bagi saya, ini bekerja daripada jawaban yang diterima oleh Gerald.
Martin Becker

1
untuk apa 'root'?
Adakah yang

19

Jangan melihat lebih jauh:

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

Pendekatan umum:

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

Keindahan tentang ini adalah Anda TIDAK perlu mengubah SHELLvariabel untuk crontab dari shmenjadibash


13

Satu-satunya cara yang benar untuk menjalankan pekerjaan python cron saat menggunakan virtualenv adalah dengan mengaktifkan lingkungan dan kemudian menjalankan python lingkungan untuk menjalankan kode Anda.

Salah satu cara untuk melakukannya adalah menggunakan virtualenv activate_thisdalam skrip python Anda, lihat: http://virtualenv.readthedocs.org/en/latest/userguide.html#using-virtualenv-without-bin-python

Solusi lain adalah menggemakan perintah lengkap termasuk mengaktifkan lingkungan dan memasukkannya ke dalam /bin/bash. Pertimbangkan ini untuk Anda /etc/crontab:

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

1
Saya sangat ingin tahu apakah ada konsensus bahwa ini sebenarnya satu-satunya cara yang benar.
Aaron Schumacher

1
Ini mungkin satu-satunya cara yang benar. Tetapi ada cara lain yang berhasil.
Will

4
Ini bukan "satu-satunya cara yang benar." Saya telah berhasil menjalankan skrip dalam virtualenv hanya dengan mengarahkan cronjob ke biner python virtualenv, seperti '/ home / user / folder / env / bin / python'. Tidak perlu mengaktifkan lingkungan apa pun.
Canucklesandwich

Jika Anda menggunakan PYTHONPATH khusus di lingkungan virtual env / bin / python tidak akan bekerja untuk Anda. Itu sebabnya penggunaan env / bin / aktif lebih baik
varela

1
itu tergantung pada bagaimana Anda mengatur PYTHONPATH dan jika Anda mengaturnya dengan cara yang mengharuskan "mengaktifkan" venv, Anda salah melakukannya

10

Alih-alih bercanda dengan shebang khusus virtualenv, cukup tambahkan PATHke crontab.

Dari virtualenv yang diaktifkan, jalankan tiga perintah dan skrip python ini hanya berfungsi:

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

Baris pertama crontab sekarang akan terlihat seperti ini:

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

12
Bukan solusi yang bagus. Setiap tugas python di crontab akan dijalankan dengan biner dari virtualenv. Membuat biner itu python pseudo-global bertentangan dengan tujuan virtualenv.
Victor Schröder

4

Solusi terbaik bagi saya adalah untuk keduanya

  • gunakan python binary di direktori venv bin /
  • mengatur jalur python untuk memasukkan direktori modules venv.

man pythonmenyebutkan memodifikasi path di shell at $PYTHONPATHatau python withsys.path

Jawaban lain menyebutkan ide untuk melakukan ini menggunakan shell. Dari python, menambahkan baris berikut ke skrip saya memungkinkan saya untuk berhasil menjalankannya langsung dari cron.

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

Begini tampilannya dalam sesi interaktif -

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

4

Saya ingin menambahkan ini karena saya menghabiskan beberapa waktu untuk menyelesaikan masalah dan tidak menemukan jawaban di sini untuk kombinasi penggunaan variabel dalam cron dan virtualenv. Jadi mungkin itu akan membantu seseorang.

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

Itu tidak berfungsi dengan baik ketika dikonfigurasi seperti

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

Terima kasih @davidwinterbottom , @ reed-sandberg dan @mkb untuk memberikan arah yang benar. Jawaban yang diterima benar-benar berfungsi dengan baik sampai python Anda perlu menjalankan skrip yang harus menjalankan biner python lain dari direktori venv / bin.


0

Ini adalah solusi yang bekerja dengan baik untuk saya.

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

Saya menggunakan miniconda dengan Conda versi 4.7.12 di Ubuntu 18.04.3 LTS.

Saya dapat menempatkan script di atas di dalam dan menjalankannya melalui crontab juga tanpa masalah.


0

skrip python

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

Perintah Cron

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

Dalam perintah di atas

  • * / 1 * * * * - Jalankan setiap minte
  • cd / Workspace / testcron / - Jalur skrip python
  • / Workspace / testcron / venvcron / bin / python3 - jalur Virtualenv
  • Workspace / testcron / testcronwithparam.py - File path
  • parameter - parameter
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.