Tuesday, November 11, 2014

camunda BPM engine: How many tasks can you execute without wait state

Today I got quite curious today about this topic and I don't know if anyone ever wondered/tried.
At work I introduced the camunda BPM engine a few months ago. One requirement was not to reach any wait state during the execution. That ways we want to make sure the process ends synchronously and we don't show stale data.

As you can image the stacktraces got pretty big when an exception occurred during the end of the process (>1000 lines). So I wondered how many tasks could be executed before the java stack is full (or anything else unexpected happens).
To try this I wrote a simple Java class:


public class Main {
private static final int NUMBER_TASKS = 100;

public static void main(String[] args) throws InterruptedException {

    ProcessEngineConfiguration configuration = ProcessEngineConfiguration
            .createStandaloneProcessEngineConfiguration();
    configuration.setJdbcUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
    configuration
            .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_CREATE_DROP);
    configuration.setJdbcUsername("sa");
    configuration.setJdbcPassword("");
    configuration.setHistory(ProcessEngineConfiguration.HISTORY_NONE);

    ProcessEngine engine = configuration.buildProcessEngine();
    BpmnModelInstance bpmn = erzeugeBpmn();
    engine.getRepositoryService().createDeployment()
            .addModelInstance("manyTasks.bpmn", bpmn).deploy();
    RuntimeService runtimeService = engine.getRuntimeService();
    ProcessInstance processInstance = runtimeService
            .startProcessInstanceByKey("manyTasks");
    System.out.println("Done");

}

private static BpmnModelInstance erzeugeBpmn() {
    AbstractFlowNodeBuilder<?, ?> builder = Bpmn.createProcess().id("manyTasks").executable().startEvent();
    for(int i = 0; i < NUMBER_TASKS; i++){
    builder = builder.serviceTask().camundaClass(EmptyDelegate.class.getName());
    }
    return builder.endEvent().done();
}

As you can see, nothing fancy (and I am still happy that there is a Java API for generating BPMN).
My computer has two Intel Core i7 with 2.9GHz and 16GB of RAM and runs Java 1.7.0_72 64bit. To run this I used the Eclipse defaults (Kepler SR2 x64):

--launcher.XXMaxPermSize
256M
--launcher.XXMaxPermSize
256m
-Xms40m
-Xmx512m


Ten and 100 tasks are no problem.
To get an overview of the size of the stacktraces I'll add a JavaDelegate, which throws an exception at the end.
So the method looks like this:

private static BpmnModelInstance erzeugeBpmn() {
   AbstractFlowNodeBuilder<?, ?> builder = Bpmn.createProcess().id("manyTasks").executable().startEvent();
      for(int i = 0; i < ANZAHL_TASKS; i++){
        builder = builder.serviceTask().camundaClass(EmptyDelegate.class.getName());
      }
      return builder.serviceTask().camundaClass(ExceptionDelegate.class.getName()).endEvent().done();
   }

Also, I'd like to see how log output grows, so here are the numbers. The additional task is always the exception task so the numbers are 11, 101, 1001...
  • 11 tasks: 392 lines log
  • 101 tasks: 1025 lines log
  • 1001 tasks: SOF
Yay, I reached the limit ;-)

Exception in thread "main" java.lang.StackOverflowError
    at java.lang.ThreadLocal$ThreadLocalMap.getEntry(ThreadLocal.java:376)
    at java.lang.ThreadLocal$ThreadLocalMap.access$000(ThreadLocal.java:261)
    at java.lang.ThreadLocal.get(ThreadLocal.java:146)
    at org.camunda.bpm.engine.impl.context.Context.getStack(Context.java:95)
    at org.camunda.bpm.engine.impl.context.Context.getCommandContext(Context.java:46)
    at org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:728)
    at org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:719)
...

It seems like I gotta take some smaller steps:
  • 501 tasks: SOF
  • 401 tasks: SOF
  • 301 tasks: SOF
  • 201 tasks: 1025 lines log
  • 151 tasks: 1025 lines log
Wait, what?
Yes, strangely Eclipse always shows me the same amount of lines for the exception after reaching a certain threshold. And no, I didn't limit the console output in Eclipse. If anyone knows why this limit exists, please let me know.

The task limit I reached was 268 tasks (267 "normal" ones and one exception task).
I am not sure about the practical implications of my "research" but as I said, I was just curious.
Maybe we can agree that processes of a certain size should reach a wait state due to organizational and technical reasons ;-)

EDIT: Please note that when executing a task as multi instance every loop counts as one (I learned that the hard way ;-) )

0 comments:

Post a Comment

 

Copyright @ 2013 Wrong tracks of a developer.

Designed by Templateiy