Linux中crontab任务计划不执行的问题分析

在使用配置crontab过程中一直不能执行配置的任务,折腾了半夜没有解决,随找到如下文章,查问题的思路很清晰,帮我找到了问题,直接转:

crond是Linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,与windows下的计划任务类似,当安装完成操作系统后,默认会安装此服务工具,并且会自动启动crond进程,crond进程每分钟会定期检查是否有要执行的任务,如果有要执行的任务,则自动执行该任务。

使用权限:
root用户和crontab文件的所有者
语法:
crontab [-e [UserName]|-l [UserName]|-r [UserName]|-v [UserName]|File ]
说明:
crontab 是用来让使用者在固定时间或固定间隔执行程序之用,换句话说,也就是类似使用者的时程表。-u user 是指设定指定 user 的时程表,这个前提是你必须要有其权限(比如说是 root)才能够指定他人的时程表。如果不使用 -u user 的话,就是表示设定自己的时程表。
参数:
-e [UserName]: 执行文字编辑器来设定时程表,内定的文字编辑器是 VI,如果你想用别的文字编辑器,则请先设定 VISUAL 环境变数来指定使用那个文字编辑器(比如说 setenv VISUAL joe)
-r [UserName]: 删除目前的时程表
-l [UserName]: 列出目前的时程表
-v [UserName]:列出用户cron作业的状态
自拉起脚本很简单,随便写几行就搞定了:
Shell
#!/bin/bash
processcount=$(pgrep my_app|wc -l)
cd $(cd $(dirname $0) && pwd)
if [[ 0 -eq $processcount ]]
then
echo “[ $(date) ] : my_app is down, start it!” | tee -ai ./checkprocess.log
bash ./start.sh #这里是项目的重启脚本
else
echo my_app is OK!
fi
然后丢到 crontab,1分钟执行一次:
Shell

* * * * * bash /data/app_server/checkprocess.sh >/dev/null 2>&1
本以为万事大吉了,结果还是坑了,进程再一次挂了,尼玛什么鬼?
一、检查日志
根据经验,先看一下crontab的日志:
tail /var/log/messages
没发现相关日志,看来不是打印到了这,于是查看了下crontab的默认日志位置:
tail /var/log/cron

Mar 25 21:40:01 li733-135 CROND[1959]: (root) CMD (sh /data/app_server/checkprocess.sh >/dev/null 2>&1)
Mar 25 21:40:01 li733-135 CROND[1960]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Mar 25 21:40:01 li733-135 CROND[1961]: (root) CMD (/usr/sbin/ntpdate pool.ntp.org > /dev/null 2>&1)
Mar 25 21:41:01 li733-135 CROND[2066]: (root) CMD (sh /data/app_server/checkprocess.sh >/dev/null 2>&1)
很明显,任务计划确实在正常执行着,看来问题在脚本上了。
二、检查脚本

①、直接执行
检查脚本第一步,直接按照crontab里面的命令行,执行脚本:
sh /data/app_server/checkprocess.sh
[ Fri Mar 25 21:25:01 CST 2016 ] : my_app is down, start it!

sh /data/app_server/checkprocess.sh
my_app is OK!
结果进程正常拉起了!
直接执行成功,而放到crontab就失败,经验告诉我肯定的脚本环境变量有问题了!
②、环境变量
于是在脚本里面载入环境变量:
#!/bin/bash
#先载入环境变量
source /etc/profile
#其他代码不变
然后手工把进程杀死,等待自拉起,结果… 还是不行!
③、系统邮件
经验告诉我,crontab执行失败,如果没有屏蔽错误的话,会产生一个系统邮件,
位置在 /var/spool/mail/root
所以,我把crontab里面的 2>&1 这个屏蔽错误先取消掉,等待几分钟查看邮件。
cat /var/spool/mail/root 发现有如下报错:

From root@free-node-us.localdomain Fri Mar 25 21:30:02 2016
Return-Path: <root@app_server.localdomain>
X-Original-To: root
Delivered-To: root@app_server.localdomain
Received: by app_server.localdomain (Postfix, from userid 0)
id 78DB5403E2; Fri, 25 Mar 2016 21:19:02 +0800 (CST)
From: root@app_server.localdomain (Cron Daemon)
To: root@app_server.localdomain
Subject: Cron <root@app_server> bash /data/app_server/checkprocess.sh >/dev/null
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
X-Cron-Env: <LANG=en_US.UTF-8>
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/root>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>
Message-Id: <20160325131902.78DB5403E2@app_server.localdomain>
Date: Fri, 25 Mar 2016 21:19:02 +0800 (CST)

start.sh: line 4: /sbin/sudo: No such file or directory #sudo命令找不到!我次奥·~
居然是脚本里面的sudo执行失败了,找不到这个文件。看来单纯的载入 profile 不一定靠谱啊!
③、修复脚本
知道问题所在,解决就简单了,粗暴点,直接写入sudo的绝对路径 /usr/bin/sudo
继续测试自拉起,结果… 还是不行!R了G了!!
三、最终解决
继续查看了下系统邮件,发现如下信息:
Subject: Cron <root@free-node-us> source /etc/profile;bash /data/app_server/checkprocess.sh >/dev/null
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
X-Cron-Env: <LANG=en_US.UTF-8>
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/root>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>
Message-Id: <20160325132403.0E8E1403E2@app_server.localdomain>
Date: Fri, 25 Mar 2016 21:24:03 +0800 (CST)

sudo: sorry, you must have a tty to run sudo #原来是这个问题!
很明显,提示了sudo必须需要tty才能执行,解决很简单,取消这个限制即可!
编辑 /etc/sudoers ,找到 Defaults requiretty, 然后注释掉这行:

vim /etc/sudoers

#Defaults requiretty
最后使用 :x! 或 :wq! 强制保存即可。
结果观察还是报了相同的错误!原来改完这个sudo并不会影响已经运行的crontab,所以需要重启crontab服务刷新下设置:

service crond restart
这下终于可以了!

四、分析总结
Linux系统里面计划任务,crontab 没有如期执行这是运维工作中比较常见的一种故障了,根据经验,大家可以从如下角度分析解决:

①、检查crontab服务是否正常
这个一般通过查看日志来检查,也就是前文提到的 /var/log/cron 或 /var/log/messages,如果里面没有发现执行记录,那么可以重启下这个服务:service crond restart
②、检查脚本的执行权限
一般来说,在crontab中建议使用 sh 或 bash 来执行shell脚本,避免因脚本文件的执行权限丢失导致任务失败。当然,最直接检查就是人工直接复制crontab -l 里面的命令行测试结果。
③、检查脚本需要用到的变量
和上文一样,通常来说从crontab里面执行的脚本和人工执行的环境变量是不一样的,所以对于一些系统变量,建议写绝对路径,或使用witch动态获取,比如 sudo_bin=$(which sudo) 就能拿到 sudo在当前系统的绝对路径了。
④、放大招:查看日志
其实,最直接最有效的就是查看执行日志了,结合crontab执行记录,以及crontab执行出错后的系统邮件,一般都能彻底找到失败的原因了!当然,要记住在crontab中如果屏蔽了错误信息,就不会发邮件了。
这又让我想起了如果crontab未屏蔽日志,可能会导致硬盘 inode 爆满

CentOS 7使用 yum 安装 MariaDB 与 MariaDB 的简单配置

1、安装MariaDB

安装命令

yum -y install mariadb mariadb-server

安装完成MariaDB,首先启动MariaDB

systemctl start mariadb

设置开机启动

systemctl enable mariadb

接下来进行MariaDB的相关简单配置

mysql_secure_installation

首先是设置密码,会提示先输入密码

Enter current password for root (enter for none):<–初次运行直接回车

设置密码

Set root password? [Y/n] <– 是否设置root用户密码,输入y并回车或直接回车
New password: <– 设置root用户的密码
Re-enter new password: <– 再输入一次你设置的密码

其他配置

Remove anonymous users? [Y/n] <– 是否删除匿名用户,回车

Disallow root login remotely? [Y/n] <–是否禁止root远程登录,回车,

Remove test database and access to it? [Y/n] <– 是否删除test数据库,回车

Reload privilege tables now? [Y/n] <– 是否重新加载权限表,回车

初始化MariaDB完成,接下来测试登录

mysql -uroot -ppassword

完成。

 

2、配置MariaDB的字符集

文件/etc/my.cnf

vi /etc/my.cnf

在[mysqld]标签下添加

init_connect='SET collation_connection = utf8_unicode_ci' 
init_connect='SET NAMES utf8' 
character-set-server=utf8 
collation-server=utf8_unicode_ci 
skip-character-set-client-handshake

文件/etc/my.cnf.d/client.cnf

vi /etc/my.cnf.d/client.cnf

在[client]中添加

default-character-set=utf8

文件/etc/my.cnf.d/mysql-clients.cnf

vi /etc/my.cnf.d/mysql-clients.cnf

在[mysql]中添加

default-character-set=utf8

全部配置完成,重启mariadb

systemctl restart mariadb

之后进入MariaDB查看字符集

mysql> show variables like "%character%";show variables like "%collation%";

显示为
+————————–+—————————-+
| Variable_name            | Value                      |
+————————–+—————————-+
| character_set_client    | utf8                      |
| character_set_connection | utf8                      |
| character_set_database  | utf8                      |
| character_set_filesystem | binary                    |
| character_set_results    | utf8                      |
| character_set_server    | utf8                      |
| character_set_system    | utf8                      |
| character_sets_dir      | /usr/share/mysql/charsets/ |
+————————–+—————————-+
8 rows in set (0.00 sec)

+———————-+—————–+
| Variable_name        | Value          |
+———————-+—————–+
| collation_connection | utf8_unicode_ci |
| collation_database  | utf8_unicode_ci |
| collation_server    | utf8_unicode_ci |
+———————-+—————–+
3 rows in set (0.00 sec)

字符集配置完成。

 

3、添加用户,设置权限

创建用户命令

mysql>create user username@localhost identified by 'password';

直接创建用户并授权的命令

mysql>grant all on *.* to username@localhost indentified by 'password';

授予外网登陆权限

mysql>grant all privileges on *.* to username@'%' identified by 'password';

授予权限并且可以授权

mysql>grant all privileges on *.* to username@'hostname' identified by 'password' with grant option;

简单的用户和权限配置基本就这样了。

其中只授予部分权限把 其中 all privileges或者all改为select,insert,update,delete,create,drop,index,alter,grant,references,reload,shutdown,process,file其中一部分。

数据库版本控制Alembic

安装:
pip3 install alembic

初始化:(如果项目中已经有了,不需要再重新初始化,请直接使用)
在工程目录新建文件夹alembic(名字可以任意),进入alembic执行:alembic init alembic
生成:
alembic.ini
alembic/versions/
alembic/env.py
alembic/script.py.mako

配置:
alembic.ini

sqlalchemy.url = driver://user:pass@localhost:port/dbname
修改为
mysql+pymysql://root:123456@192.168.0.100:3306/xxx

alembic/env.py

target_metadata = None
修改为
import os

import sys

root = os.path.dirname(__file__)+’/../../src/’
sys.path.append(root)

from db.models import Base

target_metadata = Base.metadata

自动创建版本:
alembic revision –autogenerate -m “initdb”

更新数据库:
alembic upgrade 版本号

更新到最新版
alembic upgrade head

降级数据库
alembic downgrade 版本号

更新到最初版
alembic downgrade head

离线更新(生成sql)
alembic upgrade 版本号 –sql > migration.sql

从特定起始版本生成sql
alembic upgrade 版本一:版本二 –sql > migration.sql

查询当前数据库版本号
查看alembic_version表。

清除所有版本
将versions删掉,并删除alembic_version表

平时使用:
alembic revision –autogenerate -m “”
alembic upgrade head

手机app连接智能硬件配置wifi方案

市面上已经有的关于手机app配置智能硬件主要有以下几种,
1、手机连接智能硬件的软ap,再配置
这个方式相信没有难度,手机连接上了智能硬件后,手机app和智能硬件就可以建立socket通信,然后两者之间就可以进行数据的交互,不管是设置还是传输都没有问题了。
接着手机app配置智能硬件需要连接的路由的ssid和密码,然后智能硬件就可以自行连接路由了。再接着,手机连接路由,智能硬件也连接着路由,至此以后两者就可以交互了。如果加上互联网上的服务器的话。手机通过4g网络也可以控制智能硬件。
2、 神奇的smart config
这种方式我最早知道的应该是出自TI的单片机加wifi模块之中,手机端app只需要输入ssid和密码,然后广播udp包。接着智能硬件就可以知道需要连接的路由和密码,然后就可以主动去连接路由,接着就和1中一样。
其实所谓的smart config的原理也很简单,首先app端发送带有ssid和密码的经过加密的udp广播包。其次wifi模块拥有monitor模式,也就是所谓的监听模式,可以抓取空中的包,当然,wifi必须扫描出当前的可以连接的所有路由处于哪个信道,并对这些信道分别监听,然后收到了经过加密的app端发送的包后,解密出来就是ssid和密码,接着可以通过wpa_supplicant进程来进行连接路由。
3、声波配置
这种方式现在应用挺广的,支付宝,微信等都有应用,其主要的原理就是手机放出经过编码加密的声音,智能硬件通过麦克风录音,解码解密,然后配置成功。接着就和上述基本类似
一个简单的配置可以通过很多方式,最终的目的不约而同,就是为了使用户更方便地体验产品。加上APP上的人性化设置,让用户体验十分舒服。相比而言,后面两中方式更加值得拥有,也就是所谓的一键配置功能。

Git上传过大文件时错误处理

问题:使用gogs配置的git服务器,git提交时提示文件超限

解决:通过配置nginx的文件上传限制

http {
log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent” “$http_x_forwarded_for”‘;

access_log /var/log/nginx/access.log main;

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 100m;     //配置限制100m

 

React Native启动 android例子的问题

Mac OX

1、没有找到 ANDROID_HOME

配置环境变量 vi ~/.bash_profile添加:

export ANDROID_HOME=/Users/liwf/Library/Android/sdk

使生效:source ~/.bash_profile

2、failed to find Build Tools revision 23.0.1

>cd  /Users/liwf/Library/Android/sdk/tools

查看:

     >android list sdk -a

   安装

    >android update sdk -a -u -t 12

3、No connected devices!

原因:没有启动虚拟机,先启动虚拟机即可 (我使用的Genymotion)