前言
由于业务需求,需要在固定时间启动关闭nginx,现要求上班时间每天早上9点启动nginx,下午18点关停nginx,周末都是关停。我就想着用原生java 来写个定时任务。
本项目只有一个java 单文件,简单发布运行。
一、准备环境
使用 idea 新建一个普通java 项目,代码见文章末尾
, idea 一般会自动编译后在工程目录生成 out 目录(编译后的class文件),如果没有可以手动编译。
二、使用步骤
1.打包发布
把编译后的目录 dingshi_rw 压缩上传到 nginx 服务器后解压。
2.编写启动脚本
进入 dingshi_rw 目录编写启动脚本 start.sh。
脚本内容是:
nohup java cn.com.liyx.dingshi.Dingshi > dingshi.log &
3. 运行
运行脚本如果提示 Could not find or load main class … 有可能是环境变量 CLASSPATH 配置有问题。
3.1 CLASSPATH 环境变量
在/etc/profile 文件添加 CLASSPATH 配置(有很多种配置方式,这是其一)
4.最终效果
星期五下午 18 点关闭 nginx
星期一 早上9 点启动 nginx
总结
本代码的星期几获取片段是参考网上的,看着挺复杂。
本逻辑没有每次都去检查运行状态,是为了有时候需要手动启停一段时间时,不会冲突。
启停环节和状态检查环节没有在同一轮周期,状态检查环节是在启停环节的下一个周期,为了避免脚本执行后,nginx 状态没有及时更新造成信息不一致。
使用一个内部类作为 状态 信息存储。
代码
package cn.com.liyx.dingshi;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.*;
public class Dingshi {
private static final int upTimeBegin = 9; // 运行开始时间
private static final int upTimeEnd = 18; // 运行结束时间
private static final String PS = " ps aux | grep nginx "; // 查看进程
private static final String runNginx = "/usr/local/nginx/sbin/nginx" ; // 启动 nginx
private static final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
Date date = new Date();
String format = sf.format(date);
Calendar now = Calendar.getInstance();
//一周第一天是否为星期天
boolean isFirstSunday = (now.getFirstDayOfWeek() == Calendar.SUNDAY);
//获取周几
int weekDay = now.get(Calendar.DAY_OF_WEEK);
int hour = now.get(Calendar.HOUR_OF_DAY);
//若一周第一天为星期天,则-1
if(isFirstSunday){
weekDay = weekDay - 1;
if(weekDay == 0){
weekDay = 7;
}
}
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
System.out.println("当前时间:"+ format + " 星期:" + weekDay + "; "+ hour + " 时, " + "当前 nginx 运行线程ID: " + StateInfo.pid);
/* -------------------------- */
checkUpTimeNow(hour, weekDay);
if(StateInfo.needCheck){
System.out.println(" 需要检查运行状态! ");
checkUpStateNow();
StateInfo.needCheck = false; // 不用再检查
}else {
System.out.println(" 不需要检查运行状态! ");
if(StateInfo.upTimeNow && !StateInfo.upStateNow){
// 启动
System.out.println("开始启动!");
startUp(); // 启动
StateInfo.needCheck = true; // 需要重新检查运行状态
}
if(!StateInfo.upTimeNow && StateInfo.upStateNow){
// 关闭
System.out.println("开始关闭!");
checkUpStateNow(); // 关闭之前进行进程检查, 避免其他方式重启应用, 进程ID变化
shutDown(StateInfo.pid);
StateInfo.needCheck = true; // 需要重新检查运行状态
}
}
}
},0, 60 * 1000); // 60 秒执行一次
}
/**
*
* @param hour
*
*/
public static void checkUpTimeNow(int hour, int week){
boolean ct = false;
if(week != 6 && week != 7){ // 排除周末
if(Dingshi.upTimeBegin <= hour && hour < Dingshi.upTimeEnd){
ct = true;
}
}
System.out.println(" checkUpTimeNow 是否运行时间 " + ct);
StateInfo.upTimeNow = ct;
}
public static void checkUpStateNow(){
boolean r = false; // 是否运行
String p = ""; // 线程id
try {
String[] cmd = new String[]{"/bin/sh", "-c", Dingshi.PS};
Process ps = Runtime.getRuntime().exec(cmd);
BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
StringBuffer sb = new StringBuffer();
String line;
while ((line = br.readLine()) != null) {
if(line.contains(Dingshi.runNginx) && line.contains("master")){
r = true; // 已启动
String[] split = line.split("\\s+");
p = split[1]; // 获取线程id
}
//执行结果加上回车
sb.append(line).append("\n");
}
String result = sb.toString();
System.out.println("方法 checkUpStateNow 结果:\n" + result + "\n当前是否运行 " + r + " 线程id: " + p);
} catch (Exception e) {
e.printStackTrace();
}
StateInfo.pid = p;
StateInfo.upStateNow = r;
}
public static void startUp(){
String[] cmd = new String[]{"/bin/sh", "-c", Dingshi.runNginx};
try {
Process ps = Runtime.getRuntime().exec(cmd);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("+++++++++++++++++ startUp 启动完成 ");
}
/**
*
* @param pid 线程 id
*/
public static void shutDown(String pid){
String[] cmd = new String[]{"/bin/sh", "-c", " kill " + pid};
try {
Process ps = Runtime.getRuntime().exec(cmd);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("+++++++++++++++++ shutDown 关闭完成 pid : " + pid);
}
}
/**
* 状态信息对象
*/
class StateInfo {
public static boolean needCheck = true; // 是否需要检查状态
public static boolean upTimeNow = false; // 当前是否运行时间
public static boolean upStateNow = false; // 当前是否是运行状态
public static String pid = ""; // 运行的线程id
}