一、起因
打算使用activiti的定时启动事件来定时启动流程,然后再在该流程中针对每个用户启动另外一个流程实例来计算每个用户的实时账单,系统的用户数一般是1000~2000(此处假设是2000),实时账单一般每小时计算一次,那么一天的数据量就是 2000x24=48000,一个月就是150w,一年就是1800w,这样的记录数对于activiti的历史表来说就有点多了,很怀疑他在这样的数据量下是否还可以跑得比较顺畅。我想activiti设计的初衷不是用来做这种大规模的自动触发的、没有人工参与的流程的。
所以就考虑是不是通过某些设置,可以让这种自动执行的流程不用写历史表,但是其他的需要人工参与的流程还是要能够正常记录历史记录。
二、源码阅读
然后就阅读了activiti 5.18的源码,分析如下:
写历史表示在DefaultHistoryManager,中实现的,通过HistoryLevel来控制,相关的代码如下:
public void recordProcessInstanceStart(ExecutionEntity processInstance) {
if(isHistoryLevelAtLeast(HistoryLevel.ACTIVITY)) {
HistoricProcessInstanceEntity historicProcessInstance = new HistoricProcessInstanceEntity(processInstance);
// Insert historic process-instance
getDbSqlSession().insert(historicProcessInstance);
....
}
而isHistoryLevelAtLeast的实现如下:
public boolean isHistoryLevelAtLeast(HistoryLevel level) {
if(log.isDebugEnabled()) {
log.debug("Current history level: {}, level required: {}", historyLevel, level);
}
// Comparing enums actually compares the location of values declared in the enum
return historyLevel.isAtLeast(level);
}
HistoryLevel枚举类型的是实现如下
/**
* Enum that contains all possible history-levels.
*
* @author Frederik Heremans
*/
public enum HistoryLevel {
NONE("none"),
ACTIVITY("activity"),
AUDIT("audit"),
FULL("full");
private String key;
private HistoryLevel(String key) {
this.key = key;
}
/**
* @param key string representation of level
* @return {@link HistoryLevel} for the given key
* @throws ActivitiException when passed in key doesn‘t correspond to existing level
*/
public static HistoryLevel getHistoryLevelForKey(String key) {
for(HistoryLevel level : values()) {
if(level.key.equals(key)) {
return level;
}
}
throw new ActivitiIllegalArgumentException("Illegal value for history-level: " + key);
}
/**
* String representation of this history-level.
*/
public String getKey() {
return key;
}
/**
* Checks if the given level is the same as, or higher in order than the
* level this method is executed on.
*/
public boolean isAtLeast(HistoryLevel level) {
// Comparing enums actually compares the location of values declared in the enum
return this.compareTo(level) >= 0;
}
}
可以看出,是否要在历史记录表中记录流程执行信息,是由 DefaultHistoryManager的level成员来决定的,只有在ACTIVITY及其以上级别才会记录。
DefaultHistoryManager是全局的,和某个具体的流程或者流程实例是没有关系的,所以在默认实现中,activiti不支持设置单个流程或者流程实例是否写历史记录表。
三、解决方案
如果我们真的想要实现针对每个流程或者流程实例都可以控制他是否写日志,要有两点修改:
1.要给ExecutionEntity添加一个HistoryLevel属性,或者流程变量,可能用流程变量更方便一些,就不需要对原有的类做改动了;
2.要实现一个自定义的HistoryManager,然后注入到CommandContext中。在这个自定义的HistoryManager中需要能够判断ExecutionEntity的HistoryLevel的等级,以决定是否需要记录他的历史信息;