crontab中部署Python脚本注意事项
有时候手工执行Python脚本跑的好好的,但是部署到Linux的crontab中后,就会遇到一些问题,最近终于有空整理一下这方面的内容,其实也是自己也踩了一些别人踩过的坑!这里仅仅列举个人遇到的一些小问题,经验和精力问题,不能面面俱到,仅总结一下自己遇到的这些问题。
环境变量问题
cron中的环境变量和系统的环境变量是不一样的,我们可以通过设置定时脚本将cron中的环境变量打印出来,然后一对比,你就能发现差异
* * * * * env > /tmp/env.txt
如果你Python脚本中要获取环境变量的话,那么部署到Crontab作业后就要小心了,很有可能手工运行脚本是正常的,但是部署到Crontab后运行就不正常了,如下所示,我们构造这样一个测试脚本crontab_env_test.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import logging
import os.path
import os
import base64
# 第一步,创建一个logger
logger = logging.getLogger()
logger.setLevel(logging.DEBUG) # Log等级开关
# 第二步,创建一个handler,用于写入日志文件
log_path = '/home/konglb/logs/'
log_name = log_path + 'kerry_test.log'
logfile = log_name
file_handler = logging.FileHandler(logfile, mode='a+')
file_handler.setLevel(logging.ERROR) # 输出到file的log等级的开关
# 第三步,定义handler的输出格式
formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
file_handler.setFormatter(formatter)
# 第四步,将handler添加到logger里面
logger.addHandler(file_handler)
# 如果需要同時需要在終端上輸出,定義一個streamHandler
print_handler = logging.StreamHandler() # 往屏幕上输出
print_handler.setFormatter(formatter) # 设置屏幕上显示的格式
logger.addHandler(print_handler)
db_user=os.environ.get('my_env')
print(db_user)
logger.error(db_user)
如下所示,手工执行该脚本,就会往/home/konglb/logs/kerry_test.log中写入环境变量my_env的值(/etc/profile中设置了export my_env=kerry )
# /usr/local/bin/python3.6 /home/konglb/python/crontab_env_test.py
kerry
2019-08-20 20:20:18,293 - crontab_env_test.py[line:30] - ERROR: kerry
然后我们配置crontab后,如下所示,通过刷新日志观察其获取环境变量my_env的值
# crontab -l
*/1 * * * * /usr/local/bin/python3.6 /home/konglb/python/crontab_env_test.py
如下截图所示,你会看到在Crontab中运行的Python脚本根本没有获取到环境变量my_env的值
# tail -60f kerry_test.log
2019-08-20 20:20:18,293 - crontab_env_test.py[line:30] - ERROR: kerry
2019-08-20 20:22:02,337 - crontab_env_test.py[line:30] - ERROR: None
2019-08-20 20:23:01,533 - crontab_env_test.py[line:30] - ERROR: None
2019-08-20 20:24:01,682 - crontab_env_test.py[line:30] - ERROR: None
2019-08-20 20:25:01,832 - crontab_env_test.py[line:30] - ERROR: None
2019-08-20 20:26:01,103 - crontab_env_test.py[line:30] - ERROR: None
2019-08-20 20:27:01,243 - crontab_env_test.py[line:30] - ERROR: None
2019-08-20 20:28:01,397 - crontab_env_test.py[line:30] - ERROR: None
2019-08-20 20:29:01,543 - crontab_env_test.py[line:30] - ERROR: None
2019-08-20 20:30:01,680 - crontab_env_test.py[line:30] - ERROR: None
2019-08-20 20:31:01,998 - crontab_env_test.py[line:30] - ERROR: None
2019-08-20 20:32:01,223 - crontab_env_test.py[line:30] - ERROR: None
2019-08-20 20:33:01,369 - crontab_env_test.py[line:30] - ERROR: Non
那么要如何解决这个问题呢,如下所示,在执行Python脚本时,获取/etc/profile中的系统变量(不同平台或不同环境有所区别)
*/1 * * * * source /etc/profile && /usr/local/bin/python3.6 /home/konglb/python/crontab_env_test.py
还有一种方案,就是使用shell包裹Python脚本,如下所示:
# more kerry.sh
#!/bin/bash
source /etc/profile
/usr/local/bin/python3.6 /home/konglb/python/crontab_env_test.py
*/1 * * * * /home/konglb/python/kerry.sh
相对路径问题
把上面的脚本修改一下,使用相对路径,如下所示,然后crontab作业运行时就会报错
#!/usr/bin/python
# -*- coding: utf-8 -*-
import logging
import os.path
import os
import base64
# 第一步,创建一个logger
logger = logging.getLogger()
logger.setLevel(logging.DEBUG) # Log等级开关
# 第二步,创建一个handler,用于写入日志文件
#log_path = '/home/konglb/logs/'
log_path = os.path.dirname(os.getcwd()) + '/logs/'
log_name = log_path + 'kerry_test.log'
logfile = log_name
file_handler = logging.FileHandler(logfile, mode='a+')
file_handler.setLevel(logging.ERROR) # 输出到file的log等级的开关
# 第三步,定义handler的输出格式
formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
file_handler.setFormatter(formatter)
# 第四步,将handler添加到logger里面
logger.addHandler(file_handler)
# 如果需要同時需要在終端上輸出,定義一個streamHandler
print_handler = logging.StreamHandler() # 往屏幕上输出
print_handler.setFormatter(formatter) # 设置屏幕上显示的格式
logger.addHandler(print_handler)
db_user=os.environ.get('my_env')
print(db_user)
logger.error(db_user)
其实切换到其它路径后,手工执行该脚本也会报错误,因为相对路径的设置,导致一些逻辑错误出现,如下所示,所以如果要部署为Crontab作业的Python脚本,最好使用绝对路径,避免出现这个问题。
# pwd
/root
# /usr/local/bin/python3.6 /home/konglb/python/crontab_env_test.py
Traceback (most recent call last):
File "/home/konglb/python/crontab_env_test.py", line 19, in <module>
file_handler = logging.FileHandler(logfile, mode='a+')
File "/usr/local/lib/python3.6/logging/__init__.py", line 1031, in __init__
StreamHandler.__init__(self, self._open())
File "/usr/local/lib/python3.6/logging/__init__.py", line 1060, in _open
return open(self.baseFilename, self.mode, encoding=self.encoding)
FileNotFoundError: [Errno 2] No such file or directory: '//logs/kerry_test.log'
另外,像密码过期导致crontab不执行作业(Linux账号密码过期会导致crontab作业不能执行)这样的案例也遇到过,不过这个与Python脚本无关系,如果遇到相关问题,可以从Why-Cronjob-Not-Work这篇文章介绍的这几个方面去思考、分析判断。
参考资料:
https://www.tony-yin.site/2018/10/29/Why-Crontab-Not-Work/
crontab中部署Python脚本注意事项的更多相关文章
- mac上使用crontab周期性执行python脚本
这个月买了本书<Linux系统命令及Shell脚本实践指南>, 看到了一个周期性执行任务cron.顿时产生一个想法: mac上有这种机制么? 加上自己也在15年下半年也学了点python脚 ...
- C++中调用Python脚本
C++中调用Python脚本的意义就不讲了,至少你可以把它当成文本形式的动态链接库, 需要的时候还可以改一改,只要不改变接口, C++的程序一旦编译好了,再改就没那么方便了 先看Python的代码 代 ...
- Delphi中使用python脚本读取Excel数据
Delphi中使用python脚本读取Excel数据2007-10-18 17:28:22标签:Delphi Excel python原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 . ...
- nginx tomcat 自动部署python脚本【转】
#!/usr/bin/env python #--coding:utf8-- import sys,subprocess,os,datetime,paramiko,re local_path='/ho ...
- Linux系统crontab定时调度Python脚本
Linux系统crontab定时调度Python脚本 一.Python脚本随Linux开机自动运行 #Python脚本:/home/edgar/auto.py #用root权限编辑以下文件:/etc/ ...
- C++中调用Python脚本(转载)
转载▼ 标签: 杂谈 C++中调用Python脚本的意义就不讲了,至少你可以把它当成文本形式的动态链接库,需要的时候还可以改一改,只要不改变接口, C++的程序一旦编译好了,再改就没那么方便了先看Py ...
- 使用shell程序备份crontab中的.sh脚本文件
需求 线上环境有一些定时脚本(用crontab -l可查看当前用户的),有时我们可能会改这些定时任务的脚本内容.为避免改错无后悔药,需用shell实现一个程序,定时备份crontab中的.sh脚本文件 ...
- crontab定时运行python脚本访问MySQL遇到问题
最近写了一个python脚本来定时备份MySQL数据库.具体实现如下: 1)python脚本中使用os.system("mysqldump -h127.0.0.1 -uroot -ppass ...
- crontab中运行python程序出错,提示ImportError: No module named解决全过程
将一个python脚本放入crontab执行时,提示如下错:ImportError: No module named hashlib但是在shell中直接执行时没有任何问题,google之后,得到线索 ...
随机推荐
- Linux上编译安装PHP
这篇文章主要介绍了关于Linux上编译安装PHP,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 之前在服务器上编译安装了PHP运行环境,但是安装完过了一段时间就差不多忘记了,只是零零星 ...
- 一个原生JS实现的不太成熟的贪吃蛇游戏
一个初初初初级前端民工 主要是记录一下写过的东西,复习用 大佬们如果看到代码哪里不符合规范,或者有更好写法的,欢迎各位批评指正 十分感谢 实现一个贪吃蛇游戏需要几步? 1.有地图 2.有蛇 3.有食物 ...
- 关于IDEA的Maven打jar包springboot项目问题,打成可执行jar包,IDEA创建的maven项目和spring initializr项目
Spring Initializr创建的项目 源文件地址 https://github.com/TaoPanfeng/maven-package 项目的创建步骤 进行打包 clear package ...
- [MVC]自定义模型绑定器,从表单对模型进行赋值
一.奇葩的问题 之前自己造轮子的时候,遇到一个很奇怪的问题,虽然需求很奇葩,但是还是尝试解决了一下 当提交的表单里包含多个重复名称的字段的时候,例如 <form action="/Te ...
- SD卡学习笔记
最近调试了SD卡,遇到了一些小问题,记录一下,分享一下. 1. SD卡 卡槽旁边的一个小开关 我们平时见过的SD卡都是小的SD卡,可以放在手机上的.现在大多数的开发板上也是小的SD卡的卡槽,插入 ...
- mongoDB4.0数据库
下载:https://www.mongodb.com/ 安装:略 注意:使用前修改bin目录下配置文件mongodb.cfg,删除最后一行的'mp'字段 1. 启动服务与终止服务 net start ...
- sql数据文件导入数据库
1.首先通过xshell连接数据库服务器,执行命令mysql -u root -p 命令,按照提示输入密码.连接上数据库. 2.在连接终端上执行命令create database JD_Model; ...
- Java中的接口(什么是接口,接口的好处,具体的使用)
1.什么是接口? 官方概述: 在java语言中,接口不是类,而是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义. 这种技术主要用来描述类具有什么功能,而并不给出每个类的具体实现. Bala ...
- win2008加入域控之尝试解析加入域中域控制器的dns名称失败解决办法
记录下今天遇到以前没遇到的问题 加入域的时候提示“尝试解析加入域中控制器的DNS”名称失败 可能的原因: 如果确认dns没问题 dc正常访问,那可能就是因为域控制器无法向dns注册srv记录. SRV ...
- [BZOJ5280] [Usaco2018 Open]Milking Order
Description Farmer John的N头奶牛(1≤N≤105),仍然编号为1…N,正好闲得发慌.因此,她们发展了一个与Farmer John每 天早上为她们挤牛奶的时候的排队顺序相关的复杂 ...