Cron没有运行django命令

时间:2014-03-03 13:56:39

标签: python django git ubuntu cron

我有一个django脚本,应该每天在指定的时间运行。我正在尝试使用crontab实现此目的。该脚本应该转储数据库,使用gzip对其进行存档并将其上传到bitbucket

以下是我的crontab文件的相关部分:

00 4    * * *   root    python /my_django_project_path/manage.py update_locations
47 16   * * *   root    python /my_django_project_path/manage.py database_bu

当我执行python /my_django_project_path/manage.py database_bu时,它完全正常。然而,crontab要么不执行它,要么在此过程中发生一些事情。甚至更奇怪,第一个crontab命令(update_locations)执行得非常好。

阅读this question,我尝试了以下内容,但没有成功:

将命令更改为:

47 16   * * *   root    (cd /my_django_project_path/ && python manage.py database_bu)

将命令更改为:

47 16   * * *   root    /usr/bin/python /my_django_project_path/manage.py database_bu

将以下内容添加到我的脚本中(即使没有它,另一个工作正常):

#!/usr/bin/python

from django.core.management import setup_environ
import settings
setup_environ(settings)

通过导出django项目设置的脚本运行所有内容:

/my_django_project_path/cron_command_executor.sh:

export DJANGO_SETTINGS_MODULE=my_django_project.settings 
python manage.py ${*}

crontab中的以下内容:

47 16   * * *   root    ./my_django_project_path/cron_command_executor.sh database_bu

将用户更改为我的用户和Apache用户(www-data)。

我的crontab文件末尾有换行符。

更新

执行sudo su时,手动运行该命令不再有效。它被卡住了,什么也没做。

tail -f /var/log/syslog的输出是:

Mar 3 18:26:01 my-ip-address cron[726]: (system) RELOAD (/etc/crontab) 
Mar 3 18:26:01 my-ip-address CRON[1184]: (root) CMD (python /my_django_project_path/manage.py database_bu)

更新

我正在使用以下.netrc文件来阻止git请求凭据:

machine bitbucket.org
    login myusername
    password mypassword

备份脚本的实际代码是:

import subprocess
import sh
import datetime
import gzip
from django.core.management.base import BaseCommand

class Command(BaseCommand):
    def handle(self, *args, **options):
        execute_backup()

FILE_NAME = 'some_file_name.sql'
ARCHIVE_NAME = 'some_archive_name.gz'
REPO_NAME    = 'some_repo_name'
GIT_USER = 'some_git_username' # You'll need to change this in .netrc as well.
MYSQL_USER   = 'some_mysql_user'
MYSQL_PASS   = 'some_mysql_pass'
DATABASE_TO_DUMP = 'SomeDatabase' # You can use --all-databases but be careful with it! It will dump everything!.

def dump_dbs_to_gzip():
    # Dump arguments.
    args = [
        'mysqldump', '-u', MYSQL_USER, '-p%s' % (MYSQL_PASS),
        '--add-drop-database',
        DATABASE_TO_DUMP,
    ]
    # Dump to file.
    dump_file = open(FILE_NAME, 'w')
    mysqldump_process = subprocess.Popen(args, stdout=dump_file)
    retcode = mysqldump_process.wait()
    dump_file.close()
    if retcode > 0:
        print 'Back-up error'
    # Compress.
    sql_file = open(FILE_NAME, 'r')
    gz_file = gzip.open(ARCHIVE_NAME, 'wb')
    gz_file.writelines(sql_file)
    gz_file.close()
    sql_file.close()
    # Delete the original file.
    sh.rm('-f', FILE_NAME)

def clone_repo():
    # Set the repository location.
    repo_origin = 'https://%s@bitbucket.org/%s/%s.git' % (GIT_USER, GIT_USER, REPO_NAME)

    # Clone the repository in the /tmp folder.
    sh.cd('/tmp')
    sh.rm('-rf', REPO_NAME)
    sh.git.clone(repo_origin)
    sh.cd(REPO_NAME)

def commit_and_push():
    # Commit and push.
    sh.git.add('.')
    sh.git.commit(m=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    sh.git.push('origin', 'master')
    sh.cd('..')
    sh.rm('-rf', REPO_NAME)

def execute_backup():
    clone_repo()
    dump_dbs_to_gzip()
    commit_and_push()

if __name__ == "__main__":
    execute_backup()

更新

我设法使用Chris Clark's suggestion of calling the script directly rather than through manage.py修复了它。但是,我仍然对造成这个问题的原因感兴趣,所以赏金仍然可用。

更新[求助]:

将以下行添加到/etc/environment并将其作为我的用户帐户运行而不是root用户修复它:

PWD=/my_django_project_path/helpers/management/commands

我仍然想知道为什么只有我的用户可以运行它,所以如果有人有解决方案,请提供帮助。

4 个答案:

答案 0 :(得分:2)

这让我想起了一个非常令人沮丧的陷阱。你的crontab文件末尾有换行符吗?来自man crontab:

  

... cron要求crontab中的每个条目都以换行符结尾。   如果crontab中的最后一个条目缺少换行符,cron将会   考虑crontab(至少部分)破坏并拒绝安装   它

答案 1 :(得分:2)

这也是黑暗中的一个镜头 - 我们的团队在通过cron运行管理命令时遇到了问题。我们从来没有费心去追寻它们为什么是片状的,但是经过大量的拔毛之后,我们又直接调用了python函数,而不是通过manage.py,从那以后事情一直在嗡嗡作响。

答案 2 :(得分:2)

由于 python /my_django_project_path/manage.py database_bu的某些版本适合您,这意味着问题出在您的cron environment上,或者您设置cron的方式,而不是脚本本身(如要上传的文件大小或网络连接不会导致问题)。

首先,您正在运行脚本

  

47 16 * * * root python /my_django_project_path/manage.py database_bu

您正在为其提供用户名root,该用户名与当前用户不同,而shell命令适用于您当前的用户。使用rootsudo su用户运行相同命令的事实表明您的root用户帐户无法正确配置。 FWIW,几乎总是应该避免以root身份安排某些东西,因为它可能导致奇怪的文件权限问题。

因此,请尝试从当前用户安排您的cron作业。

47 16 * * * cd /my_django_project_path/ && python manage.py database_bu

这可能仍然无法完全运行cron作业。在这种情况下,问题可能出在两个地方 - 您的shell环境中有一些cron环境中缺少的变量,或者您的.netrc文件没有正确读取凭据,或者两者都没有。

根据我的经验,我发现PATH变量导致最多的麻烦,所以在你的shell上运行echo $PATH,如果你获得的路径值是/some/path:/some/other/path:/more/path/values,那么运行你的cron像

这样的工作
47 16 * * * export PATH="/some/path:/some/other/path:/more/path/values" && cd /my_django_project_path/ && python manage.py database_bu

如果这不成功,请检查下一步的所有环境变量。

使用普通shell中的printenv > ~/environment.txt来获取shell中设置的所有环境变量。然后使用以下cron条目* * * * * printenv > ~/cron_environment.txt来识别cron环境中缺少的变量。或者,您可以使用脚本中的代码段从脚本

获取环境的值
import os
os.system("printenv")

比较两者,找出不同的任何其他相关变量(如HOME),并尝试在script / cron条目中使用相同的变量来检查它们是否有效。

如果事情仍然无法解决,那么我认为剩下的问题应该是.netrc中的bitbucket凭据,其中保存了用户名和密码。内容.netrc可能在cron环境中不可用。

相反,请为您的帐户创建并set up an ssh keypair,让备份发生在ssh而不是https上(如果您在此步骤中生成没有密码的ssh密钥,则更好,以避免ssh-keys'陷阱)。

设置ssh密钥后,您必须编辑项目根目录的.git/config文件中的现有原始网址(或者必须使用{{1}添加新的远程origin_ssh对于ssh协议)。

请注意,repo的git remote add origin_ssh url个网址与https类似,而ssh的网址与https://user@bitbucket.org/user/repo.git类似。

PS:git@bitbucket.org:user/repo.git,或者更确切地说bitbucket不是备份的理想解决方案,为了更好的备份策略,有大量的线程可供使用。此外,在调试时,每分钟运行一次你的crons(git),或者以相同的低频率运行你的crons以便更快地调试。

修改

OP在评论中表示设置* * * * *变量对他有效。

  

PWD = / my_django_project_path / helpers / management /命令到/ etc / environment

这是我之前建议的,shell中可用的环境变量之一不存在于cron环境中。

通常,crown总是以减少的环境变量和权限集运行,设置正确的变量将使cron工作。

此外,由于您使用的是PWD文件,因此该帐户特定于您的帐户,因此不适用于任何其他帐户(包括.netrc sudo帐户}),除非您在其他帐户中配置相同的设置。

答案 3 :(得分:0)

我不太擅长阅读strace输出,但我认为the one you posted表示您的程序已调用git并正在等待其终止。你提到上传到BitBucket,所以这里是在黑暗中拍摄git试图推送到ssh遥控器;当你自己运行它时,ssh-agent会透明地验证你;但是当你以root身份运行它时,没有ssh-agent,因此git会提示输入ssh密码并等待你的输入。

尝试在git下手动执行sudo su调用并检查。

如果这没有用,你需要得到git的输出(或者你实际在那里调用的任何东西)。检查documentation for the sh package以获取有关如何重定向标准输出和标准错误的详细信息。