Custom Job Handler Registration (doesn't seem to register)

This is related to another ticket I had logged, but in that case it was the syntax flat-out not working. The approach I have got now appears to register my custom job handler, except that the call back never gets fired. I’ve compared this against a spring boot demo I obtained and the sprint boot approach is executing the custom job while my manual attempt ignores it. Not sure what’s going on. The custom job handler looks like this:

public class CustomJobHandler implements JobHandler {

public static final String TYPE = "cutomJobType";

@Override
public String getType() {
	return TYPE;
}

@Override
public void execute(JobEntity job, String configuration, VariableScope variableScope,CommandContext commandContext) {
	
CommandContextUtil.getProcessEngineConfiguration(commandContext).getTaskService().complete(taskId, variableMap);
	
	CommandContextUtil.getProcessEngineConfiguration(commandContext).getTaskService().complete(configuration);
}

}

My code for manually registering the custom job looks like this:

public class FlowableEngine {

public FlowableEngine() {}

public ProcessEngine buildEngine(String jdbcUrl, String userName, String password) {
	System.out.println("Creating flowable engine");
	
	ProcessEngineConfigurationImpl config = (ProcessEngineConfigurationImpl) ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
	
	System.out.println("Created standalone config for engine construction");
	
	BasicDataSource datasource = new BasicDataSource();
	datasource.setDriverClassName("oracle.jdbc.OracleDriver");
	datasource.setUrl(jdbcUrl);
	datasource.setUsername(userName);
	datasource.setPassword(password);
	config.setDatabaseSchemaUpdate(AbstractEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
	config.setDatabaseType(AbstractEngineConfiguration.DATABASE_TYPE_ORACLE);
	config.setDataSource(datasource);
	config.setAsyncExecutorActivate(true);

	System.out.println("Set the configuration");
	
	JobHandler packageJob =  new CustomJobHandler();
	
	List<JobHandler> customHandlers = new ArrayList<JobHandler>();
	customHandlers.add(packageJob);

	config.setCustomJobHandlers(customHandlers);

	System.out.println("Registered custom job handlers");
	
	ProcessEngine engine = config.buildProcessEngine();

	System.out.println("Created the engine");

	return engine;
}

}

And then I have this little bit of code that actually tries to schedule the job and fire it off:

public static void scheduleAsyncJob(ProcessEngine engine, String jobHandlerType, String jobConfig) {

	ManagementService managementService = engine.getManagementService();
	managementService.executeCommand(new Command<String>() {	
				
		public String execute(CommandContext commandContext) {
	    
		    JobService jobService = CommandContextUtil.getJobService(commandContext);	    
			JobEntity job = jobService.createJob();
			job.setJobHandlerType(jobHandlerType);
			job.setJobHandlerConfiguration(jobConfig);
			jobService.createAsyncJob(job, false);
			jobService.scheduleAsyncJob(job);
			return "scheduled";
		}
	});
}

On the spring boot side of things, this is the bean definition that registers the handler:

public class MyApp {

public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}

@Bean
public EngineConfigurationConfigurer customEngineConfiguration() {
return engineConfiguration -> {
engineConfiguration.addCustomJobHandler(new CustomJobHandler());
};
}

}
And here’s the service function that fires it off:

public void scheduleTaskUpdate(String taskId) {
managementService.executeCommand(new Command() {

		public String execute(CommandContext commandContext) {
	    
		    JobService jobService = CommandContextUtil.getJobService(commandContext);
		    
		    JobEntity job = jobService.createJob();
		    job.setJobHandlerType(CustomJobHandler.TYPE);		    
		    
		    job.setJobHandlerConfiguration(taskId);
		    
		    jobService.createAsyncJob(job, false);    
		    jobService.scheduleAsyncJob(job);
		    return "scheduled";
	    
		}
	});		
}

The CustomJobHandler.java is the same code, so my only difference bewteen these approaches seems to be how I register the custom job handler. And I cannot figure out what I’m doing wrong with the procedural approach that Spring does differently.

Hi Jeff,

Hard to guess, Is job executor activated?

Regards
Martin

Shouldn’t this activate the job executor? How do I programmatically confirm the job executor is active?

I have some workflows in my system that use HTTP services which are configured to run async and the jobs get picked up and run after a while. That would seem to indicate I have the job executor active, but that doesn’t mean it’s set to run properly for custom jobs.

I believe the Configurer comes too late. The javadoc seems to indicate it’s called when values have already been set - i.e. the job handlers have already been initialized.

You could try to swap to a EngineConfigurator and set it in the beforeInit.

Ok, that makes some logical sense, given that the only difference between the Spring approach and my DIY attempt is that I’m not getting the job handler to register. If it’s already been setup then it’s ignoring me and not inserting it into the engine configuration. I will have to look up how to use an EngineConfigurator and how to specify the configuration during the beforeInit cycle, but at least this gives me a direction to go instead of scratching my head (because I was about to end up down a major rabbit hole of Spring and the AsyncTaskExecutors).

So trying this with a beforeInit() is getting me lost in what feels like a chicken and the egg loop. The configurator looks like it takes an engine config as the input, but I need the configurator to be able to set up the configuration of the job handler. Is there an example somewhere in the JUnit tests of doing this? I couldn’t find it but there’s a lot of code and I wouldn’t know where to start hunting.

Hey @jeff.gehly,

Using the EngineConfigurationConfigurer is the right way to do it. That is actually invoked before any EngineConfigurator is called.

However, the way you are registering the Spring Bean is incorrect.

You are registering a raw EngineConfigurationConfigurer bean. This bean is not injected in the right place as it doesn’t match the auto wire signature. You can try this by putting a break point in the invocation of the configurer and you’ll see.

What you need to do is:

@Bean
public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> customEngineConfiguration() {
	return engineConfiguration -> {
		engineConfiguration.addCustomJobHandler(new CustomJobHandler());
	};
}

Note the <SpringProcessEngineConfiguration>.

Cheers,
Filip

Edit: Looks like when I copy/pasted my code it stripped off the Generic typing to the @Bean registration. I checked my code example for Spring and it looks precisely as you described it should (which would explain why the SpringBoot example is working).

Where I’m stumped is that I need to pull this apart and do it via a line-by-line approach where I don’t use Spring and have to define a builder function that configures the process engine and registers my job handler. That approach compiles and runs without tanking, but my job handler is clearly NOT registered (because it doesn’t run the handler’s execute() function). The current working theory is that I’m waiting until it’s too late to register my handler, but to get at it earlier I’m using classes that I am having a hard time finding examples of (this being a very advance feature of the framework that doesn’t have a ton of documentation on it).

I tried doing this:

ProcessEngineConfigurationImpl config = (ProcessEngineConfigurationImpl) ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();

… (sets datasource attributes) …

JobHandler packageJob = new CustomJobHandler();

	List<JobHandler> customHandlers = new ArrayList<JobHandler>();
	customHandlers.add(packageJob);
	
	
	config.setCustomJobHandlers(customHandlers);

ProcessEngineConfigurator engineConfigurator = new ProcessEngineConfigurator();
engineConfigurator.beforeInit(config);

	ProcessEngine engine = engineConfigurator.getProcessEngineConfiguration().buildProcessEngine();

But end up getting errors thrown about the DbSqlSessionFactory not being initialized properly, and that’s taking me down a whole rabbit hole that suggests I did something wrong. My experience with Flowable to date has indicated that usually if I start getting explosions deep in the API stack I did something wrong during the setup.

Totally unrelated: How do I get source code to show up properly in the quote-window approach? Right now I’m just copy/pasting my code and it seems to grab some of it but ignores other parts. Figure if I’m going to post lots of code snippets I should figure out how to format it so it’s easier to read for you.