Cron และ virtualenv


227

ฉันพยายามเรียกใช้คำสั่งการจัดการ Django จาก cron ฉันกำลังใช้ virtualenv เพื่อให้โครงการของฉันแซนด์บ็อกซ์

ฉันได้เห็นตัวอย่างที่นี่และที่อื่น ๆ ที่แสดงคำสั่งการจัดการจากภายใน virtualenv ชอบ:

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

อย่างไรก็ตามแม้ว่า syslog จะแสดงรายการเมื่องานควรเริ่มทำงาน แต่งานนี้จะไม่ทำงานจริง ๆ (ไฟล์บันทึกสำหรับสคริปต์นั้นว่างเปล่า) ถ้าฉันเรียกใช้บรรทัดด้วยตนเองจากเปลือกมันทำงานตามที่คาดไว้

วิธีเดียวที่ฉันสามารถรับคำสั่งให้ทำงานผ่าน cron ในขณะนี้คือการแบ่งคำสั่งและวางไว้ในสคริปต์ bash wrapper:

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

แก้ไข:

ars เกิดขึ้นพร้อมชุดคำสั่งที่ใช้งานได้:

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

อย่างน้อยในกรณีของฉันการเรียกใช้สคริปต์เปิดใช้งานสำหรับ virtualenv ไม่ได้ทำอะไรเลย ใช้งานได้ดีกับการแสดง


ข้อแตกต่างอย่างหนึ่งที่ฉันเห็นคือสคริปต์จะเรียกใช้งาน Manage.py พร้อมกับ / home / user / project เป็นไดเรกทอรีทำงานปัจจุบัน คำสั่ง cron ของคุณจะถูกเรียกใช้กับโฮมไดเร็กตอรี่ของคุณเป็น cwd อาจมีล็อกไฟล์หรือไม่
rettops

ที่จริงแล้วมีการกำหนดเส้นทางบันทึกอย่างแน่นอนมันไม่ได้สร้าง / ต่อท้ายเพราะสคริปต์ไม่ได้ทำงานอยู่
John-Scott

วิธีแก้ปัญหาที่รวดเร็วและสกปรกสำหรับปัญหา cron คือการถ่ายโอนข้อมูลสภาพแวดล้อมของคุณ (ซึ่งคำสั่งของคุณทำงานอย่างลึกลับ) envและexportพวกมันทั้งหมดในชุดคำสั่งbash script ที่คุณเรียกใช้จาก crontab
jberryman

คำตอบ:


250

คุณควรจะสามารถทำได้โดยใช้pythonในสภาพแวดล้อมเสมือนของคุณ:

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

แก้ไข: หากโครงการ django ของคุณไม่ได้อยู่ใน PYTHONPATH คุณจะต้องเปลี่ยนไปใช้ไดเรกทอรีที่ถูกต้อง:

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

คุณสามารถลองบันทึกความล้มเหลวจาก cron:

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

อีกสิ่งที่ควรลองคือการเปลี่ยนแปลงmanage.pyสคริปต์ของคุณที่ด้านบนสุด:

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

1
ที่ยังใช้งานไม่ได้ ลืมใส่ไว้ในรายการสิ่งที่ไม่ทำงาน ใช่ฉันสามารถเรียกใช้คำสั่งนั้นด้วยตนเองในเชลล์ แต่ไม่สามารถใช้งานได้จาก cron
John-Scott

คุณแทนที่~ด้วยเส้นทางแบบเต็มหรือไม่? (คุณอาจจะทำเพียงแค่การทำให้แน่ใจว่า ... )
อาร์

อาคุณได้ตัวอย่างการทำงานมาแล้ว! ฉันได้ลองทุกชุดและเปิดใช้งาน virtualenv ดูเหมือนจะไม่มีผลใด ๆ ฉันตั้ง PYTHONPATH ของฉันเป็น. bashrc แต่ cron นี้เห็นได้ชัดว่าไม่ได้ใช้? จะอัปเดตคำถามของฉันเพื่อเน้นคำตอบของคุณ
John-Scott

ใช่ฉันลืมไปว่า cron ทำงานภายใต้สภาพแวดล้อมที่น้อยมาก คำแนะนำทั่วไปคือการเขียนสคริปต์ทุบตีเพื่อตั้งค่าสภาพแวดล้อมที่งานของคุณจะต้อง คุณสามารถลองหาโปรไฟล์ทุบตีโดยตรงใน cron แต่สิ่งนี้อาจนำไปสู่ข้อบกพร่องที่ละเอียดอ่อนขึ้นอยู่กับสิ่งที่อยู่ในโปรไฟล์ของคุณ (บางทีถ้าคุณมีโปรไฟล์แยกต่างหากและน้อยที่สุดสำหรับความต้องการดังกล่าว
ARS

7
วิธีทดสอบที่ดีคือเรียกใช้งาน / bin / sh จากนั้นลองเรียกใช้คำสั่งของคุณจากที่นั่น อย่างน้อยคุณจะมีการตั้งค่าสภาพแวดล้อมเช่นเดียวกับ cron
Dick

98

วิ่งsourceจาก cronfile จะไม่ทำงานตามที่ใช้ cron เป็นเริ่มต้นเปลือกของมันซึ่งไม่ได้รับการสนับสนุน/bin/sh sourceคุณต้องตั้งค่าตัวแปรสภาพแวดล้อม SHELL เป็น/bin/bash:

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

มันเป็นการยากที่จะทราบว่าเหตุใดจึงล้มเหลวเนื่องจาก/var/log/syslogไม่บันทึกรายละเอียดข้อผิดพลาด ดีที่สุดที่จะตั้งชื่อแทนตัวเองให้รูทเพื่อให้คุณได้รับอีเมลพร้อมข้อผิดพลาด cron เพียงแค่เพิ่มตัวเองไปและเรียกใช้/etc/aliasessendmail -bi

ข้อมูลเพิ่มเติมที่นี่: http://codeinthehole.com/archives/43-Running-django-cronjobs-within-a-virtualenv.html

ลิงค์ด้านบนเปลี่ยนเป็น: https://codeinthehole.com/tips/running-django-cronjobs-within-a-virtualenv/


12
หรือ '.' (คำสั่ง dot) ซึ่งรองรับโดย / bin / sh. /path/to/virtualenv/bin/activate
Reed Sandberg

5
DavidWinterbottom ถ้านั่นคือชื่อจริงของคุณคุณคือฮีโร่ของฉัน ฉันไม่เคยรู้เกี่ยวกับ sh vs bash และซอร์สไฟล์ คุณได้ส่องแสงสว่างให้กับเพื่อน ๆ ในโลกของฉัน ขอบคุณ
joemurphy

หากคุณมีpostactivateไฟล์คุณควรจะทำsource /path/to/virtualenv/bin/activate && source /path/to/virtualenv/bin/postactivate
dspacejs

1
ขอบคุณ! สำหรับฉันมันใช้งานได้ดีกว่าคำตอบที่เจอรัลด์ยอมรับ
Martin Becker

1
'รูต' สำหรับทำอะไร ใครสามารถอธิบายได้
adnanmuttaleb

19

อย่ามองเพิ่มเติม:

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

วิธีการทั่วไป:

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

ความงามของเรื่องนี้คือคุณไม่จำเป็นต้องเปลี่ยนSHELLตัวแปรสำหรับ crontab จากshเป็นbash


13

วิธีที่ถูกต้องเพียงวิธีเดียวในการรันงาน pron cron เมื่อใช้ virtualenv คือการเปิดใช้งานสภาพแวดล้อมจากนั้นเรียกใช้งาน python ของสภาพแวดล้อมเพื่อเรียกใช้โค้ดของคุณ

วิธีหนึ่งในการทำเช่นนี้คือใช้ virtualenv activate_thisในสคริปต์ python ของคุณดู: http://virtualenv.readthedocs.org/en/latest/userguide.html#using-virtualenv-without-bin-python

/bin/bashการแก้ปัญหาก็คือการสะท้อนคำสั่งที่สมบูรณ์รวมทั้งการเปิดใช้งานสภาพแวดล้อมและท่อลงใน พิจารณาสิ่งนี้สำหรับคุณ/etc/crontab:

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

1
ฉันอยากรู้อยากเห็นมากว่ามีฉันทามติว่านี่เป็นวิธีที่ถูกต้องเท่านั้น
Aaron Schumacher

1
นี่อาจเป็นวิธีที่ถูกต้องเท่านั้น แต่มีวิธีอื่นที่ใช้งานได้
จะ

4
นี่ไม่ใช่ "วิธีที่ถูกต้องเท่านั้น" ฉันได้ดำเนินการสคริปต์ใน virtualenv สำเร็จแล้วเพียงแค่ชี้ cronjob ไปที่ไพ ธ อนของ virtualenv เช่น '/ home / user / folder / env / bin / python' ไม่จำเป็นต้องเปิดใช้งานสภาพแวดล้อมใด ๆ
Canucklesandwich

หากคุณใช้ PYTHONPATH แบบกำหนดเองใน env / bin / python สภาพแวดล้อมเสมือนจะไม่ทำงานสำหรับคุณ นั่นเป็นเหตุผลว่าทำไมการใช้ env / bin / เปิดใช้งานจึงดีกว่า
varela

1
มันขึ้นอยู่กับวิธีที่คุณตั้ง PYTHONPATH และหากคุณตั้งค่าในแบบที่ต้องใช้ "การเปิดใช้งาน" venv คุณจะทำผิด

10

แทนที่จะเล่นแร่แปรธาตุกับ shebangs เฉพาะ virtualenv เพียงแค่เติมPATHลงบน crontab

จาก virtualenv ที่เปิดใช้งานให้รันทั้งสามคำสั่งและสคริปต์ python ควรทำงาน:

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

บรรทัดแรกของ crontab ควรมีลักษณะเช่นนี้:

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

12
ไม่ใช่ทางออกที่ดี งานไพ ธ อนทั้งหมดใน crontab จะทำงานด้วยไบนารีจาก virtualenv การทำให้ไบนารี่นั้นกลายเป็นงูหลามหลอกระดับโลกเทียบกับจุดประสงค์ของ virtualenv
Victor Schröder

4

ทางออกที่ดีที่สุดสำหรับฉันคือสำหรับทั้งคู่

  • ใช้ python binary ใน venv bin / directory
  • กำหนดเส้นทางของหลามเพื่อรวมไดเรกทอรีโมดูล venv

man pythonกล่าวถึงการปรับเปลี่ยนเส้นทางในเชลล์ที่$PYTHONPATHหรือในหลามด้วยsys.path

คำตอบอื่น ๆ พูดถึงแนวคิดในการทำสิ่งนี้โดยใช้เชลล์ จากไพ ธ อนการเพิ่มบรรทัดต่อไปนี้ในสคริปต์ของฉันทำให้ฉันสามารถเรียกใช้งานได้โดยตรงจาก cron

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

นี่คือลักษณะที่ปรากฏในเซสชันแบบโต้ตอบ -

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

ฉันต้องการที่จะเพิ่มเพราะฉันใช้เวลาในการแก้ปัญหาและไม่พบคำตอบที่นี่สำหรับการรวมกันของการใช้ตัวแปรใน cron และ virtualenv ดังนั้นบางทีมันจะช่วยใครบางคน

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

มันทำงานได้ไม่ดีเมื่อมีการกำหนดค่าเช่น

DIR_SMTH = "cd / smth &&. venv / bin / เปิดใช้งาน"

ขอบคุณ@davidwinterbottom , @ reed-sandbergและ@mkb ที่ให้ทิศทางที่ถูกต้อง คำตอบที่ได้รับการยอมรับใช้งานได้จริงจนกว่างูเหลือมของคุณจะต้องเรียกใช้สคริปต์ซึ่งต้องใช้ไพ ธ อนอื่นจากไดเรกทอรี venv / bin


0

นี่เป็นวิธีแก้ปัญหาที่ทำงานได้ดีสำหรับฉัน

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

ฉันใช้ miniconda กับ Conda เวอร์ชั่น 4.7.12 บน Ubuntu 18.04.3 LTS

ฉันสามารถวางข้างต้นในสคริปต์และเรียกใช้ผ่าน crontab เช่นกันโดยไม่มีปัญหา


0

สคริปต์หลาม

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

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

ในคำสั่งดังกล่าว

  • * / 1 * * * * - ดำเนินการทุก ๆ มินต์
  • cd / Workspace / testcron / - เส้นทางของสคริปต์ไพ ธ อน
  • / Workspace / testcron / venvcron / bin / python3 - เส้นทาง Virtualenv
  • พื้นที่ทำงาน / testcron / testcronwithparam.py - พา ธ ไฟล์
  • พารามิเตอร์ - พารามิเตอร์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.