前言
okey,通过前面的两篇文章,关于这个任务执行这一块,我想应该是明白了。但是这里的话,还是不够的。我们希望对于任务还可以做到执行失败的重试执行,关于这个意外宕机的一个状态恢复。
当然这里要说的是,由于完整的实现,就是按照那种牛逼的标准来实现的话,这个实现确实很复杂,要考虑的情况也非常多,这个是没有办法的事情。所以这里只能实现一个简单的。
这里的话又不得不提到我们一开始,对于这个任务清单和任务清单项的一个类型的处理了:
我们主要有这几个类型:
package com.huterox.todoscheduler.core.enumType;
import java.io.Serializable;
/**
* TodoItem类型,是必须要坚持执行,还是非必须
* */
public enum TodoItemElementType implements Serializable {
/**
* 是不是必须要执行,也就是说,如果当前这个item执行失败,整个
* 清单任务执行失败
* */
MUSTITEM("MUSTITEM"),
/**
* 执行失败可以跳过,注意,这个时候,重启的时候是不会管这个的
* */
CONTINUTEITEM("CONTINUTEITEM");
private String elementCode;
TodoItemElementType(String s) {
this.elementCode = s;
}
public String getElementCode() {
return elementCode;
}
public void setElementCode(String elementCode) {
this.elementCode = elementCode;
}
}
package com.huterox.todoscheduler.core.enumType;
import java.io.Serializable;
/**
* 任务清单对应的类型
* */
public enum TodoListElementType implements Serializable {
/**
* 宕机之后重启先执行修复函数然后继续执行没有完成的任务的模式
* */
StrongConsistency("StrongConsistency"),
/**
* 宕机之后重启执行修复,但是不继续执行任务
* */
WeakConsistency("WeakConsistency"),
/**
* 宕机之后重启不执行任何操作
* */
NothingConsistency("NothingConsistency");
private String elementCode;
TodoListElementType(String s) {
this.elementCode = s;
}
public String getElementCode() {
return elementCode;
}
public void setElementCode(String elementCode) {
this.elementCode = elementCode;
}
}
所以我们此时还涉及到这个。
恢复执行流程
那么在这里的话,我们就需要先聊到这个恢复的执行流程。
这里的话主要先看到这个接口:
package com.huterox.todoscheduler.core.scheduler;
/**
* 定制任务执行器,在这块的话,主要是扫描失败任务
* 让后尝试恢复任务,以及服务器宕机之后对任务的恢复
* */
public interface SchedulerEx {
//恢复任务
void repairTask();
//重新执行失败的任务
void againTask();
//定时扫描失败的进程你
void DaemonScheduling();
}
所以看到这个我估计你应该是明白了它的一个操作:
失败任务执行
首先,在这里我们先来看到对于失败任务的执行。在这里的话,注意看到这个东西:
我们的话在这些方法执行的时候的话,会保存状态,这个状态的保存的话,还是通过这个JDK的一个Serilizable接口来做。这里的话,不存在传输的问题,直接存,然后解析即可。
package com.huterox.todoscheduler.common;
import java.io.File;
import java.io.*;
public class SerializationUtils implements Serializable {
private static final String DEFAULT_DIRECTORY = "src/main/resources";
public static void serializeObject(Object object, String fileName) {
serializeObject(object, DEFAULT_DIRECTORY, fileName);
}
public static Object deserializeObject(String fileName) {
return deserializeObject(DEFAULT_DIRECTORY, fileName);
}
public static void serializeObject(Object object, String directory, String fileName) {
try {
// 创建目录
File dir = new File(directory);
if (!dir.exists()) {
if (dir.mkdirs()) {
System.out.println("目录已创建: " + directory);
} else {
System.out.println("无法创建目录: " + directory);
return;
}
}
// 序列化对象
FileOutputStream fileOut = new FileOutputStream(directory + "/" + fileName);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(object);
out.close();
fileOut.close();
System.out.println("对象已序列化并保存到文件: " + directory + "/" + fileName);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Object deserializeObject(String directory, String fileName) {
Object object = null;
try {
// 反序列化对象
FileInputStream fileIn = new FileInputStream(directory + "/" + fileName);
ObjectInputStream in = new ObjectInputStream(fileIn);
object = in.readObject();
in.close();
fileIn.close();
System.out.println("从文件中反序列化出对象: " + directory + "/" + fileName);
} catch (Exception e) {
e.printStackTrace();
}
return object;
}
public static void deleteSerializedObject(String directory, String fileName) {
try {
File file = new File(directory + "/" + fileName);
if (file.exists()) {
if (file.delete()) {
System.out.println("文件删除成功: " + directory + "/" + fileName);
} else {
System.out.println("无法删除文件: " + directory + "/" + fileName);
}
} else {
System.out.println("文件不存在: " + directory + "/" + fileName);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
然后在执行的时候,我们把失败的任务放在这里:
package com.huterox.todoscheduler.core.global;
import com.huterox.todoscheduler.common.SerializationUtils;
import com.huterox.todoscheduler.core.execute.proxy.TodoListExBean;
import java.io.Serializable;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 执行失败的清单对象列表
* 冷知识:CopyOnWriteArrayList 支持直接迭代删除
* */
public class TodoListFailedList implements Serializable {
private static volatile List list;
private TodoListFailedList() {}
public static List getInstance() {
if (list == null) {
synchronized (TodoListFailedList.class) {
if (list == null) {
list = new CopyOnWriteArrayList();
}
}
}
return list;
}
public static List addFailedWithSerializable(TodoListExBean todoListExBean) {
if (list == null) {
synchronized (TodoListFailedList.class) {
if (list == null) {
list = new CopyOnWriteArrayList();
}
}
}
list.add(todoListExBean);
//把这个list进行备份,这里面存放了失败的执行清单,所以这个时候要注意恢复
SerializationUtils.serializeObject(list,"failedCatalogue","catalogue.ser");
return list;
}
public static List addFailed(TodoListExBean todoListExBean) {
if (list == null) {
synchronized (TodoListFailedList.class) {
if (list == null) {
list = new CopyOnWriteArrayList();
}
}
}
list.add(todoListExBean);
return list;
}
}
所以的话,你可以直接找到这个东西,然后在对应目录去找到,然后实例化,然后去执行:
public void againTask() {
//重新执行失败任务
Object deserializeObject = SerializationUtils
.deserializeObject("failedCatalogue", "catalogue.ser");
if (deserializeObject!=null){
CopyOnWriteArrayList failedCatalogue = (CopyOnWriteArrayList) deserializeObject;
for(TodoListExBean todoListExBean:failedCatalogue){
if(todoListExBean.getExTimes()