一、起因
打算使用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的等級,以決定是否需要記錄他的歷史信息;