I have a ServiceTask which I want to retry R12/PT15M on failure before automatically opening an incident but only for specific exception i.e. RetryException.
I dont want to do any retry if i get NonRetryException and would like it to open an incident immediately.
So, how can I tell the JobExecutor not to retry for NonRetryException exception?
@cute1boy retry configuration in camunda will retry for configured number if exception occurs. So If you want to retry for certain exceptions, you can use Spring retry template in your Java Delegate/ Listeners.
I think Spring Retry inside delegate wont be much useful as it will block job scheduler thread unless all spring retries exhaust and it will cause the task to fail.
I havent tested this, but perhaps this code snippet will work…
try {
//
// Your code which throws Retry and Non Retry exceptions
//
}
catch (NonRetryException ex) {
//
// Set retry to zero and rethrow the exception. An incident is created due to the exception
Context.getJobExecutorContext().getCurrentJob().setRetries(0);
throw ex;
}
That fail fast helps in a different situation where we want to continue on a different path.
Here, we just want to open an incident, stay on the same node and wait for someone to take action.
Thats true, however you could create an open incident and route the process to a user task pending operator intervention. Thus when the incident is resolved, an operator claims the user task for completion. The user task can then route back to the original service task.
So in summary, throwing a BpmnError gets around the retry strategy, use a user task to halt progress until the incident is resolved…
Perhaps not as elegant as you desire, but it is a feasible work around…
Late response, but it can be useful for others.
It is possible by overriding the FailedJobCommandFactory class. Create you own class that return a customized DefaultJobRetryCmd.
For example @Component
public class MyFailedJobCommandFactory implements FailedJobCommandFactory {
public MyFailedJobCommandFactory() {
}
@Override
public Command<Object> getCommand(String jobId, Throwable exception) {
return new MyJobRetryCmd(jobId, exception);
}
}
Then, the MyJobRetryCmd could look like this
public class TalosJobRetryCmd extends DefaultJobRetryCmd {
public TalosJobRetryCmd(String jobId, Throwable exception) {
super(jobId, exception);
}
@Override
protected FailedJobRetryConfiguration getFailedJobRetryConfiguration(JobEntity job, ActivityImpl activity) {
// if exception is marked as no retry, we return a configuration with 1 retry, otherwise default behaviour.
if (this.exception instanceof NoRetryException) {
return new FailedJobRetryConfiguration(1, List.of("PT0M"));
} else {
return super.getFailedJobRetryConfiguration(job, activity);
}
}
}
It is now just a matter to plug the factory into Camunda configuration.
public class MyFailedJobConfiguration extends SpringProcessEnginePlugin implements CamundaFailedJobConfiguration {
private FailedJobCommandFactory failedJobCommandFactory;
public MyFailedJobConfiguration(FailedJobCommandFactory failedJobCommandFactory) {
this.failedJobCommandFactory = failedJobCommandFactory;
}
@Override
public void preInit(ProcessEngineConfigurationImpl configuration) {
if (configuration.getCustomPostBPMNParseListeners() == null) {
configuration.setCustomPostBPMNParseListeners(new ArrayList<>());
}
configuration.getCustomPostBPMNParseListeners().add(new DefaultFailedJobParseListener());
configuration.setFailedJobCommandFactory(failedJobCommandFactory);
}
}
@Configuration
public class BpmnConfiguration {
@Bean
public static CamundaFailedJobConfiguration failedJobConfiguration(MyFailedJobCommandFactory myFailedJobCommandFactory) {
return new MyFailedJobConfiguration(MyFailedJobCommandFactory);
}
}