我有一个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的build议直接调用脚本,而不是通过manage.py 。 不过,我仍然对造成这个问题的感兴趣,所以赏金仍然可用。
更新[已解决]:
将以下行添加到/etc/environment
并以我的用户帐户而不是root用户身份运行它:
PWD=/my_django_project_path/helpers/management/commands
我仍然想知道为什么只有我的用户可以运行它,所以如果有人有解决scheme,请贡献。
由于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命令适用于您当前的用户。 使用sudo su
root
用户没有运行相同的命令,这表明您的root用户帐户无法正确配置。 FWIW,以root身份安排某些事情几乎总是可以避免的,因为这会导致文件权限问题。
所以请尝试从当前用户调度您的cron作业。
47 16 * * * cd /my_django_project_path/ && python manage.py database_bu
这可能仍然不能完全运行cron作业。 在这种情况下,问题可能出现在两个地方 – 您的shell环境有一些cron环境中缺少的变量,或者您的.netrc
文件没有被正确读取,或者两者都没有正确读取.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
如果这不起作用,请检查所有的环境变量。
使用printenv > ~/environment.txt
从一个正常的shell获取在shell中设置的所有环境变量。 然后使用以下cron条目* * * * * printenv > ~/cron_environment.txt
来识别cron环境中缺少的变量。 或者,您可以使用脚本中的代码片段从脚本中获取环境的值
import os os.system("printenv")
比较两者,找出不同的其他相关变量(如HOME
),并尝试在脚本/ cron条目中使用相同的变量来检查它们是否工作。
如果事情仍然没有解决,那么我认为剩下的问题应该是在.netrc
中用你的bitbucket凭证保存用户名和密码。 内容.netrc
可能在cron环境中不可用。
相反,为你的帐户创建和设置一个ssh密钥对,让备份通过ssh
而不是https
(如果你在这一步没有通过密码生成一个ssh密钥,避免ssh-key的陷阱,那么它会更好)。
一旦你设置了ssh密钥,你将相应地必须从项目根.git/config
文件编辑现有的源URL(或者使用git remote add origin_ssh url
添加一个新的远程origin_ssh
到ssh协议)。
需要注意的是, https
url是https://user@bitbucket.org/user/repo.git
而ssh则是git@bitbucket.org:user/repo.git
。
PS: bitbucket
,或者说git
并不是备份的理想解决方案,为了实现更好的备份策略,还有大量的线程挂起。 另外,在调试时,每分钟运行一次crons( * * * * *
),或者以相似的低频率运行,以加快调试速度。
编辑
OP在评论中说,设置PWD
变量为他工作。
PWD = / my_django_project_path / helpers / management /命令到/ etc / environment
这是我之前提出的建议,在shell中可用的环境变量之一不在cron环境中。
一般来说,皇冠总是以减少的环境变量和权限运行,设置正确的变量将使cron工作。
此外,由于您正在使用.netrc
文件进行权限设置,因此该帐户特定于您的帐户,因此这不适用于任何其他帐户(包括root
帐户的sudo
帐户),除非您在另一个帐户中将相同的设置配置为好。
这让我想起了一个非常令人沮丧的问题。 你的crontab文件最后有换行符吗? 从man crontab:
… cron要求crontab中的每个条目以换行符结尾。 如果crontab中的最后一个条目缺少换行符,cron将会考虑crontab(至少部分)破坏并拒绝安装它。
这也是黑暗中的一个镜头 – 我们的团队通过cron运行管理命令时遇到了问题。 我们从来没有打算去找出它们为什么是片状的,但是在经过大量的拉动之后,我们直接调用python函数,而不是通过manage.py来处理事情。
我不是很擅长阅读strace
输出,但是我认为你发布的那个表明你的程序已经调用了git
并且正在等待它的终止。 你提到上传到BitBucket,所以这是一个黑暗的镜头 : git
试图推送到一个SSH远程; 当你自己运行它时, ssh-agent
透明地验证你; 但是当你以root身份运行它时,没有ssh-agent
,因此git
会提示输入ssh密码并等待你的输入。
尝试在sudo su
下手动执行git
调用并检查。
如果这没有帮助,你需要得到git
的输出(或者你在那里调用的任何东西)。 查看sh
包的文档以获取有关如何重定向标准输出和标准错误的详细信息。