cancel
Showing results for 
Search instead for 
Did you mean: 

Using CDI from JobExecutor

naag
Champ in-the-making
Champ in-the-making
Hi all,

we're looking for ways on how we can make use of CDI services from activities executed by the JobExecutor in JBoss AS 7. In http://forums.activiti.org/en/viewtopic.php?f=6&t=4167 Daniel suggested to write a JCA connector and use @MessageDriven beans. I've never done any JCA connectors before and also I cannot find a lot of documentation about it (maybe looking in the wrong place…). Also we would like to stick to a "pure" JBoss AS 7, so no fox platform ce.

Does anybody have an idea what could be a solution? I was thinking along the lines of having a thread pool provided by JBoss, and then using that instead of the default Java ThreadPool that Activiti uses. But I'm not even sure if that makes sense?

By the way, we're mainly looking to make @Inject work. Of course @RequestScoped and so on won't work.

Thanks for all ideas 🙂
Peter
19 REPLIES 19

frederikherema1
Star Contributor
Star Contributor
Using a JBOSS-provided pool would definitely make sense.. The job-executor can be subclassed to run the acquired jobs in that pool, rather than in a default java-threadpool, like the DefaultJobExecutor uses.

naag
Champ in-the-making
Champ in-the-making
So you think that CDI services would then be available? I'm not too familiar yet with the inner workings of CDI and documentation is a little bit sparse 😞

frederikherema1
Star Contributor
Star Contributor
My knowledge of CDI isn't that great rather. Not sure if "being in the right thead-context" would give access to the beans. Let alone that annotation-resolving would occur. That's more something for a CDI-expert I'm afraid as I only know the basics

naag
Champ in-the-making
Champ in-the-making
OK, I will try to figure it out with the CDI / JCA spec. There must be something somewhere…! Also from Daniel's post in the thread I posted above, it seems that fox platform supports this use case. So somehow, it must be possible. I try to keep this updated here.

naag
Champ in-the-making
Champ in-the-making
Short update: implementing a custom JobExecutor turns out to be quite easy, and we can send JMS messages from it to a @MessageDriven bean. That bean has CDI services enabled and will execute the job via managementService.executeJob(). Some code:


import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.inject.Inject;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

import org.activiti.engine.ProcessEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@MessageDriven(activationConfig = {
  @ActivationConfigProperty(propertyName = "destination", propertyValue = "java:/jms/queue/activitiJobExecutor"),
  @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
  @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") })
public class JobExecutorBean implements MessageListener {

protected static Logger log = LoggerFactory.getLogger(JobExecutorBean.class);

@Inject
protected ProcessEngine processEngine;

@Override
public void onMessage(Message message) {
  String jobId = getJobIdFromMessage(message);

  if (jobId != null) {
   processEngine.getManagementService().executeJob(jobId);
  }
}

protected String getJobIdFromMessage(Message message) {
  if (message instanceof TextMessage) {
   try {
    TextMessage textMessage = (TextMessage) message;
    log.debug("Recevied message over JMS: '{}'", textMessage.getText());
    return textMessage.getText();
   } catch (JMSException e) {
    log.error("Error occured while reading JMS TextMessage", e);
    return null;
   }
  }

  return null;
}
}

The custom JobExecutor basically just connects to the JMS queue obtained via JNDI and posts the Job IDs to that queue in it's executeJobs() method. Basically the MDB replaces the class ExecutorJobsRunnable which DefaultJobExecutor uses to run jobs in it's thread pool. Both ExecutorJobsRunnable and the MDB rely on ExecuteJobsCmd() to do the rest 🙂 Of course this is totally untested, but in case anybody has the same requirement, it might be helpful…

Now let's take a serious look at fox platform ce where this is supposed to be all pretty 🙂

ronald_van_kuij
Champ on-the-rise
Champ on-the-rise
Does this also work for timers? And auto acknowledge? Isn't that dangerous in case of failures?

naag
Champ in-the-making
Champ in-the-making
I just tested it with timers, it works.

Of course you're right, it's pretty untested at the moment. For example JMS will, in our current configuration, try to deliver the message up to 10 times in case of a failure. By acknowledging manually and setting up JMS properly, I think the issues can be avoided. This was just a quick test to see if things work together in general.

So yes, there are still some kinks and also it's still not 100% Java EE compatible because the JobExecutor still uses a Thread for AcquireJobsRunnable.

bernd_ruecker
Champ in-the-making
Champ in-the-making
Hi Naag.

It is actually not that different from what we do in the fox platform enterprise edition. But there are quite some nuts and bults to figure out and it might even depend on the JBoss version you are using (see https://app.camunda.com/confluence/display/foxUserGuide/Install+fox+platform+on+JBoss+AS+7#Installfo... for various bugs we are facing). We basically do the whole stuff in a Java EE 6 compliant way (JCA indeed), so we have the stuff ready for Glassfish and the rest as well. But unfortunately the EE parts of that story are not open source (but we deliver all sources to our customers), but let me know if it is interesting for you anyway.

Cheers
Bernd

dguggi
Champ in-the-making
Champ in-the-making
I'd be interested how your implementation behaves in respect to exclusive-jobs:

does your custom job-executor (or maybe the activiti base class you extend - didn't check source yet) provide the (http://activiti.org/userguide/#exclusiveJobs) feature?

i think that even if the your custom-job does exclusiveJobs, I'm afraid you may be run into problems, because you send async (jms) messages per jobId (means your impl actually does not support exclusive-jobs feature) - the application-server will typically process messages in parallel.

so if I'm correct this could be solved with
a) ensure sequential processing of messages (which is actually bad imho)
b) use advanced messaging-features (e.g. activemq's messagedestinations etc.)

did you address/solve this issue using jms/mdbs?

besides that, the solution feels somehow hacky/(way too) complex to me (imho too much overhead)
jobexecutor with threadpool => asynchronous jms messaging => mdb

daniel