camunda-community-hub / camunda-platform-7-osgi

OSGi integration for Camunda Platform 7
Apache License 2.0
22 stars 24 forks source link

Time duration behaviour - Default configuration for job execution #43

Closed avan2s closed 7 years ago

avan2s commented 7 years ago

Hi, :-) currently i am having problems with the OSGI-version of Camunda to bring a simple timer duration event to work. As described in this it seems to be that "waiting 10 seconds from now on" is not possible with the default job-configuration. 1 Minute is the smallest value. That is okay for me too, when testing it. My timer event is waiting endless... It never ends. I have defined it in the bpmn file as:

<timerEventDefinition>
  <timeDuration>PT1M</timeDuration>
</timerEventDefinition>

The token arrives, but it never leaves...

We are running it on Apache karaf with Jetty installed. 1) Do you know if timer events are working fine in context of osgi? 2) How can i define the timer duration correctly? I just want to wait 1 minute or if possible 10 seconds if the job-configuration can be adjusted.

UPDATE: I have tested PT1M out in a usual spring-environment and there it is working fine. It seems to be, that you have to configure something in the osgi- environment. The job executor seems to be active in my osgi-environment too, because, when i run after the timer-duration event is reached: List<Job> joblist = this.processEngine.getManagementService().createJobQuery().list();

it shows me the timer event... Do you have an idea, how i can use the timer-duration event correctly or is it a bug?

Thanks a lot in advance Andy

rbraeunlich commented 7 years ago

Hi Andy,

to answer your questions:

  1. I don't know why it shouldn't work. The OSGi extension does not replace the JobExecutor so it should does its thing. Maybe you could provide a unit test so I could take a better look at it. But so far I've never used the event within the OSGi context.
  2. This is more a general camunda BPM question. I can only point you to the documentation here and the Wikipedia article

Cheers, Ronny

avan2s commented 7 years ago

Hi Ronny, thank you for your quick reply. The documentation is fine and PT1M is working fine for me in a non-osgi-environment. Strange thing...

Cheers, Andy

rbraeunlich commented 7 years ago

I suppose it must be the JobExecutor or somethig related to it. Does the job arrive in the database?

avan2s commented 7 years ago

Yes it arrives in the database :) This is my simple process... image

After starting the instance, the joblist contains the timer in this list...

Map<String, String> properties = this.processEngine.getManagementService().getProperties();
    System.out.println("PROPERTIES: \n" + properties);
List<Job> joblist = this.processEngine.getManagementService().createJobQuery().list();
    System.out.println("JOBS:");
    for(Job job : joblist){
      System.out.println("ProcessDefinitionKey: " + job.getProcessDefinitionKey());
      System.out.println("suspended: " + job.isSuspended());
      System.out.println("retries: " + job.getRetries());
      System.out.println("exception-message: " + job.getExceptionMessage());
    }

gives me:

{next.dbid=101, historyLevel=2, schema.version=fox, deployment.lock=0, schema.history=create(fox)} JOBS: ProcessDefinitionKey: TEST suspended: false retries: 3 exception-message: null

rbraeunlich commented 7 years ago

Do you use the "basic" OSGi extension or an extended one like Blueprint or OSGiProcessApplication? And why is your schema.version fox? Shouldn't it be camunda?

avan2s commented 7 years ago

We are using Blueprint, but we have extended BL EL resolver with our own one in order to use DMN like this (workaround for us to use dmn and solve this issue.

public class BlueprintELResolver extends org.camunda.bpm.extension.osgi.blueprint.BlueprintELResolver {

  private static final Logger LOGGER = LoggerFactory.getLogger(BlueprintELResolver.class);
  private Map<String, JavaDelegate> delegateMap = new HashMap<String, JavaDelegate>();
  private Map<String, TaskListener> taskListenerMap = new HashMap<String, TaskListener>();
  private Map<String, ActivityBehavior> activityBehaviourMap = new HashMap<String, ActivityBehavior>();

  @Override
  public Object getValue(ELContext context, Object base, Object property) {
    if (base == null) {
      // according to javadoc, can only be a String
      String key = (String) property;
      for (String name : delegateMap.keySet()) {
        if (name.equalsIgnoreCase(key)) {
          context.setPropertyResolved(true);
          return delegateMap.get(name);
        }
      }
      for (String name : taskListenerMap.keySet()) {
        if (name.equalsIgnoreCase(key)) {
          context.setPropertyResolved(true);
          return taskListenerMap.get(name);
        }
      }
      for (String name : activityBehaviourMap.keySet()) {
        if (name.equalsIgnoreCase(key)) {
          context.setPropertyResolved(true);
          return activityBehaviourMap.get(name);
        }
      }

      VariableContext variableContext = (VariableContext) context.getContext(VariableContext.class);
      if (variableContext != null) {
        if (VAR_CTX_KEY.equals(property)) {
          context.setPropertyResolved(true);
          return variableContext;
        }
        TypedValue typedValue = variableContext.resolve((String) property);
        if (typedValue != null) {
          context.setPropertyResolved(true);
          return unpack(typedValue);
        }
      }

    }

    return null;
  }

  @Override
  public void bindService(JavaDelegate delegate, Map props) {
    String name = (String) props.get("osgi.service.blueprint.compname");
    delegateMap.put(name, delegate);
    LOGGER.info("added Camunda service to delegate cache {}", name);
  }

  @Override
  public void unbindService(JavaDelegate delegate, Map props) {
    String name = (String) props.get("osgi.service.blueprint.compname");
    if (delegateMap.containsKey(name)) {
      delegateMap.remove(name);
    }
    LOGGER.info("removed Camunda service from delegate cache {}", name);
  }

  public void bindTaskListenerService(TaskListener delegate, Map props) {
    String name = (String) props.get("osgi.service.blueprint.compname");
    taskListenerMap.put(name, delegate);
    LOGGER.info("added Camunda service to delegate cache {}", name);
  }

  public void unbindTaskListenerService(TaskListener delegate, Map props) {
    String name = (String) props.get("osgi.service.blueprint.compname");
    if (taskListenerMap.containsKey(name)) {
      taskListenerMap.remove(name);
    }
    LOGGER.info("removed Camunda service from delegate cache {}", name);
  }

  public void bindActivityBehaviourService(ActivityBehavior delegate, Map props) {
    String name = (String) props.get("osgi.service.blueprint.compname");
    activityBehaviourMap.put(name, delegate);
    LOGGER.info("added Camunda service to activity behaviour cache {}", name);
  }

  public void unbindActivityBehaviourService(ActivityBehavior delegate, Map props) {
    String name = (String) props.get("osgi.service.blueprint.compname");
    if (activityBehaviourMap.containsKey(name)) {
      activityBehaviourMap.remove(name);
    }
    LOGGER.info("removed Camunda service from activity behaviour cache {}", name);
  }

  public boolean isReadOnly(ELContext context, Object base, Object property) {
    return true;
  }

  public void setValue(ELContext context, Object base, Object property,
                       Object value) {
  }

  public Class<?> getCommonPropertyType(ELContext context, Object arg) {
    return Object.class;
  }

  public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context,
                                                           Object arg) {
    return null;
  }

  public Class<?> getType(ELContext context, Object arg1, Object arg2) {
    return Object.class;
  }

  protected Object unpack(TypedValue typedValue) {
    if (typedValue != null) {
      return typedValue.getValue();
    }
    return null;
  }
}

Btw. i have done the same console output in a Spring-environment, where the timer event is working fine. Here you can see the object's contents. The dueDate seems to be ok and registers 1 minute from now on, but it is never fired. Furthermore the processinstance-id is looking strange.

Working version in default Spring-environment:

Data on starting instance: Fri Apr 07 14:20:41 CEST 2017
Management-Service-Properties: {next.dbid=1, schema.version=fox, historyLevel=3, deployment.lock=0, schema.history=create(fox)}
Job:TimerEntity[repeat=null, id=9dab9aa7-1b8c-11e7-a0d0-54ab3a0294d6, revision=1, duedate=Fri Apr 07 **14:21:41** CEST 2017, 
                lockOwner=null, lockExpirationTime=null, executionId=9dab9aa5-1b8c-11e7-a0d0-54ab3a0294d6, processInstanceId=9dab9aa3-1b8c-11e7-a0d0-54ab3a0294d6, 
                isExclusive=true, retries=3, jobHandlerType=timer-intermediate-transition, jobHandlerConfiguration=IntermediateThrowEvent_1n8xc5j, 
                exceptionByteArray=null, exceptionByteArrayId=null, exceptionMessage=null, deploymentId=9d9616c1-1b8c-11e7-a0d0-54ab3a0294d6]
Priority 0
Suspendedfalse

Non working versin in OSGI-environment:
Processinstance-Start Datetime: Fri Apr 07 14:37:13 CEST 2017
Management-Service-Properties: {next.dbid=2101, historyLevel=2, schema.version=fox, deployment.lock=0, schema.history=create(fox)}
JOBS:
Job:TimerEntity[repeat=null, id=2021, revision=1, duedate=Fri Apr 07 14:38:13 CEST 2017, lockOwner=null, lockExpirationTime=null, executionId=2019, processInstanceId=2017, 
                isExclusive=true, retries=3, jobHandlerType=timer-intermediate-transition, jobHandlerConfiguration=IntermediateThrowEvent_1j9iuag, 
                exceptionByteArray=null, exceptionByteArrayId=null, exceptionMessage=null, deploymentId=2013]
Priority 1
Suspendedfalse

UPDATE: When i call this.processEngine.getManagementService().executeJob(job.getId()); then the event is fired directly and the service task "step1" is called. So the relation between instance and job seems to be correct. I don't know why it is waiting infinite time...

avan2s commented 7 years ago

I have tested some things out. In a nutshell you can say: 1) The engine adds the instance-execution of the timer process in ACT_RU_EXECUTION 2) The engine adds the execution of the timerevent at time t with due date (t+1 minute) with active state true 3) In spring it is deleting the execution from ACT_RU_EXECUTION, when the due date is reached. In my OSGI-context it never deletes the execution from the table.

So it seems to be, that the engine is never informed about firing the event, when the due date is reached. Also there is no log in ACT_HI_JOB_LOG.

rbraeunlich commented 7 years ago

Hi Andy, I wonder, do you have any idea, why the IDs in your OSGi environment all look like 20xx? Looking at your output I see ... id=2021 ... executionId=2019, processInstanceId=2017.... This seems way too regular for the usual IDs that are present within camunda.

avan2s commented 7 years ago

Hi Ronny, sorry for the late answer. I don't know why there are processinstance ids like 2xxx, The camunda-scripts are identically. Maybe that has something to do with our internal configuration.

However i could solve the job executor problem. We have used our own JTA-Configuration Factory and the method: JtaProcessEngineConfiguration conf = new JtaProcessEngineConfiguration(); conf.setJobExecutorActivate(true);

was never called. Now it is working fine. This issue can be closed.

Cheers, Andy

rbraeunlich commented 7 years ago

Hi Andy,

glad to hear that you could fix your! Explicitely activating the job executor can be annoying sometimes ;)

Cheers, Ronny