Thanks for the reply. So I have also come up with this solution which works, but was wondering if it could be improved.
So the timer configuration is now
<bpmn:startEvent id="Process_Start_Timer" name="start Process">
<bpmn:outgoing>SequenceFlow_0loyj3j</bpmn:outgoing>
<bpmn:timerEventDefinition>
<bpmn:timeCycle xsi:type="bpmn:tFormalExpression">${process.startTime}</bpmn:timeCycle>
</bpmn:timerEventDefinition>
</bpmn:startEvent>
The spring config bean
@Component
@Getter
public class ProcessConfiguration {
private static Map<String, String> timerDefinitions = new HashMap<>();
public ProcessConfiguration(
@Value("${process.startTime:0 0 19 ? * * TZ Europe/Paris}") String processStartTime) {
timerDefinitions.put("process.startTime", processStartTime);
}
public String getTimerDefinition(String startTimer) {
return timerDefinitions.get(startTimer);
}
}
and our custom CycleBusinessCalendar
@AllArgsConstructor
public class TZCycleBusinessCalendar extends CycleBusinessCalendar {
public static final String NAME = "cycle";
private ProcessConfiguration processConfiguration;
@Override
public Date resolveDuedate(String duedateDescription) {
return resolveDuedate(duedateDescription, null);
}
@Override
public Date resolveDuedate(String duedateDescription, Date startDate) {
try {
// replace description from config if needed
duedateDescription = Optional.ofNullable(processConfiguration.getTimerDefinition(duedateDescription))
.orElse(duedateDescription);
if (duedateDescription.startsWith("R")) {
return super.resolveDuedate(duedateDescription, startDate);
}
String[] cronExpression = duedateDescription.split(" TZ ", 2);
if (cronExpression.length == 2) {
TimeZone tz = TimeZone.getTimeZone(cronExpression[1].trim());
CronTrigger ct = new CronTrigger(cronExpression[0], tz);
SimpleTriggerContext triggerContext = new SimpleTriggerContext();
triggerContext.update(null, null, ClockUtil.getCurrentTime());
return ct.nextExecutionTime(triggerContext);
} else {
return super.resolveDuedate(duedateDescription, startDate);
}
} catch (Exception e) {
}
}
}
and on application startup we call the recalculateJobDueDate only on start timers
@Component
@AllArgsConstructor
public class StartTimerRecalculate implements ApplicationListener<ProcessApplicationStartedEvent> {
private ManagementService managementService;
@Override
public void onApplicationEvent(ProcessApplicationStartedEvent event) {
managementService.createJobQuery()
.timers()
.list()
.stream()
.map(job -> (TimerEntity)job)
.filter(timerEntity -> "timer-start-event".equals(timerEntity.getJobHandlerType()))
.forEach(timerEntity -> managementService.recalculateJobDuedate(timerEntity.getId(), true));
}
}
Is there a better point to do the recalculate?