DSL简介
DSL是一种工具,它的核心价值在于,它提供了一种手段,可以更加清晰地就系统某部分的意图进行沟通。
这种清晰并非只是审美追求。一段代码越容易看懂,就越容易发现错误,也就越容易对系统进行修改。因此,我们鼓励变量名要有意义,文档要写清楚,代码结构要写清晰。基于同样的理由,我们应该也鼓励采用DSL。
按照类型,DSL可以分为三类:内部DSL(Internal DSL)、外部DSL(External DSL)、以及语言工作台(Language Workbench)。
Internal DSL是一种通用语言的特定用法。用内部DSL写成的脚本是一段合法的程序,但是它具有特定的风格,而且只用到了语言的一部分特性,用于处理整个系统一个小方面的问题。 用这种DSL写出的程序有一种自定义语言的风格,与其所使用的宿主语言有所区别。例如我们的状态机就是Internal DSL,它不支持脚本配置,使用的时候还是Java语言,但并不妨碍它也是DSL。
builder.externalTransition()
.from(States.STATE1)
.to(States.STATE2)
.on(Events.EVENT1)
.when(checkCondition())
.perform(doAction());
状态机领域模型:
鉴于我们的诉求是实现一个仅支持简单状态流转的状态机,该状态机的核心概念如下图所示,主要包括:
State:状态
Event:事件,状态由事件触发,引起变化
Transition:流转,表示从一个状态到另一个状态
External Transition:外部流转,两个不同状态之间的流转
Internal Transition:内部流转,同一个状态之间的流转
Condition:条件,表示是否允许到达某个状态
Action/process:动作,到达某个状态之后,可以做什么
StateMachine:状态机
状态机实现:
根据上述的状态机整个核心语义模型,调度器实现的部分核心代码如下所示:
public class TaskStateMachineFactory {
private static final Map<TaskStatus, Map<String, TaskProcessor>> statusMachineMaps = new ConcurrentHashMap<>();
static {
// define task status transition relations
addTransition(TaskStatus.none, "preparing", new TaskPreparingProcessor());
addTransition(TaskStatus.none, "recovering", new TaskRecoveringProcessor());
addTransition(TaskStatus.preparing, "running", new TaskRunningProcessor());
addTransition(TaskStatus.preparing, "failed", new TaskPreparingFailedProcessor());
addTransition(TaskStatus.preparing, "disabled", new TaskDisabledProcessor());
addTransition(TaskStatus.preparing, "skipped", new TaskSkippedProcessor());
addTransition(TaskStatus.preparing, "kill", new TaskPreparingKillProcessor());
addTransition(TaskStatus.preparing, "patching", new TaskPatchingProcessor());
addTransition(TaskStatus.running, "finished", new TaskFinishedProcessor());
addTransition(TaskStatus.running, "failed", new TaskFailedProcessor());
addTransition(TaskStatus.running, "decommission", new TaskDecommissionedProcessor());
addTransition(TaskStatus.running, "kill", new TaskKillProcessor());
addTransition(TaskStatus.running, "failed_succeeded", new TaskFailedSucceededProcessor());
addTransition(TaskStatus.running, "lost", new TaskLostProcessor());
addTransition(TaskStatus.recovering, "running", new TaskRunningProcessor());
addTransition(TaskStatus.recovering, "failed", new TaskFailedProcessor());
addTransition(TaskStatus.recovering, "disabled", new TaskDisabledProcessor());
addTransition(TaskStatus.recovering, "skipped", new TaskSkippedProcessor());
addTransition(TaskStatus.recovering, "kill", new TaskKillProcessor());
addTransition(TaskStatus.recovering, "patching", new TaskPatchingProcessor());
addTransition(TaskStatus.finished, "zombie", new TaskZombieProcessor());
addTransition(TaskStatus.failed, "zombie", new TaskZombieProcessor());
addTransition(TaskStatus.decommissioned, "zombie", new TaskZombieProcessor());
addTransition(TaskStatus.killed, "zombie", new TaskZombieProcessor());
addTransition(TaskStatus.failed_succeeded, "zombie", new TaskZombieProcessor());
addTransition(TaskStatus.lost, "zombie", new TaskZombieProcessor());
}
/**
* add state transition processor
*
* @param preStatus
* @param eventName
* @param processor
*/
public static void addTransition(TaskStatus preStatus, String eventName, TaskProcessor processor) {
if (statusMachineMaps.get(preStatus) != null) {
statusMachineMaps.get(preStatus).put(eventName, processor);
} else {
Map<String, TaskProcessor> eventMap = new ConcurrentHashMap<>();
eventMap.put(eventName, processor);
statusMachineMaps.put(preStatus, eventMap);
}
}
/**
* handle task event with proper processor and transfer task state
*
* @param preStatus
* @param taskEventInfo
*/
public static TaskEventResult doTransition(TaskStatus preStatus, TaskEventInfo taskEventInfo) throws NaviException {
Map<String, TaskProcessor> eventMap = statusMachineMaps.get(preStatus);
TaskEvent event = taskEventInfo.getTaskEvent();
if (eventMap == null || eventMap.get(event.getEventName()) == null) {
TaskEventResult result = new TaskEventResult();
result.setProcessInfo(
"[ERROR] Can not process event " + event.getEventName() + " when task status is " + preStatus
.toString());
result.setSuccess(false);
return result;
}
TaskProcessor processor = eventMap.get(event.getEventName());
return processor.process(taskEventInfo);
}
}
注意:其中XXXProcessor即为到达某个状态后需要执行的处理器方法,TaskStatus定义了所有任务状态,EventName为触发的事件名称,addTransition方法定义了所有状态之间的流转关系,doTransition方法明确了如何处理正确的状态以及流转至下一状态的过程。