Hello,
We are using Flowable 6.8.0. Last week, we experienced an Out Of Memory problem. After investigation, we discovered the issue in the following code:
Flowable.getInstance().historyService().createHistoricProcessInstanceQuery()
.processInstanceId(processInstanceId)
.singleResult();
The issue was caused by the processInstanceId parameter being null, which resulted in loading over 6 million rows from the database.
Of course, passing processInstanceId == null was an error in our source code. However, in MyBatis, a null value is interpreted as simply ignoring the condition:
<sql id="commonInstanceQuerySql">
<if test="processInstanceId != null">
${queryTablePrefix}PROC_INST_ID_ = #{processInstanceId, jdbcType=NVARCHAR}
</if>
</sql>
Questions:
-
Should methods like
processInstanceIdallownullas a parameter? If not, perhaps some validation should be added. If yes, maybe you should keep null in value holder, so MyBatis would add the conditionPROC_INST_ID_ = nullinstead of ignoring it. -
Let’s look at the method
org.flowable.common.engine.impl.query.AbstractQuery.executeSingleResult(CommandContext)which is implemented like this:
public U executeSingleResult(CommandContext commandContext) {
List<U> results = executeList(commandContext);
if (results.size() == 1) {
return results.get(0);
} else if (results.size() > 1) {
throw new FlowableException("Query returned " + results.size() + " results instead of max 1");
}
return null;
}
The above implementation could be improved to be faster and to avoid OutOfMemory errors. Simply replace
List<U> results = executeList(commandContext);
with
List<U> results = listPage(0, 2);