Cron没有运行django命令


问题内容

我有一个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)也执行得很好。

阅读此问题,我尝试了以下操作,但未成功:

将命令更改为:

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的建议(而不是通过manage.py)直接调用脚本
来修复它。但是,我仍然对导致此问题的原因感兴趣,因此仍可以使用赏金。

更新[已解决]:

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

PWD=/my_django_project_path/helpers/management/commands

我仍然想知道为什么只有我的用户才能运行它,所以如果有人对此有解决方案,请做出贡献。


问题答案:

由于 某些版本 的文件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命令时,您将为它提供一个用户名,该用户名不同于当前用户。不能从root用户使用运行同一命令的事实sudo su表明,您的root用户帐户无论如何都没有正确配置。FWIW,几乎总是应避免以root用户身份进行调度,因为这可能会导致奇怪的文件权限问题。

因此,请尝试按以下方式从当前用户安排您的cron作业。

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

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

根据我的经验,我发现PATH变量会引起最多的麻烦,因此请echo $PATH在您的shell上运行,如果您获得的路径值为/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

如果仍然无法解决,请接下来检查所有环境变量。

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

import os
os.system("printenv")

比较两者,找出其他所有不同的相关变量(例如HOME),然后尝试在脚本/ cron条目中使用相同的变量以检查它们是否起作用。

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

相反,请为您的帐户创建并设置一个ssh密钥对,然后进行备份ssh而不是https(最好在此步骤中生成不带口令的ssh密钥,以避免ssh-
key的陷阱)。

一旦你已经安装SSH密钥,你将有相应的编辑现有的源URL从.git/config你的项目的根文件(或将要增加一个新的远程origin_ssh使用git remote add origin_ssh urlSSH协议)。

请注意,https回购的网址就像https://user@bitbucket.org/user/repo.gitssh一样git@bitbucket.org:user/repo.git

PS:bitbucketgit不是理想的备份解决方案,有成千上万的线程徘徊以寻求更好的备份策略。另外,在调试时,请每分钟(* * * * *)或以类似的低频率运行您的任务,以加快调试速度。

编辑

OP在评论中说,设置PWD变量对他有效。

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

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

通常,Crown总是以减少的一组环境变量和权限运行,并且设置正确的变量将使cron起作用。

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