I have a thread which needs to run essentially immediately on the first run, and every 60 seconds after that. Normally I could simply use one of the rate/delay registration methods on ExecutionManager. In this particular case, however, it is important that the timing actually line up at the turn of each minute. I noticed the following method and decided to try and use it.
public void register(String owner, String name, SelfSchedulingRunnable command);
This worked out very well as far as scheduling goes. The problem I ran into is that when I call unregister for this SelfSchedulingRunnable, it gets removed from the execution status page only temporarily until it revives itself at the turn of the next minute. Is there any way to get it to unregister fully such that currently scheduled runs at the time of calling unregister do not take place? I can keep track of some flag variable that allows me to return immediately from run() and return 0 from getNextExecDelayMillis() to prevent further scheduling, but things would be a lot cleaner in my case if the unregister simply ended everything. I know that I could also chain this together manually using successive executeOnce() calls as needed, but I prefer the diagnostics in the status page that actual scheduling provides.
Below is code that demonstrates this behavior.
@Override
public void registerSelfSchedulingRunnable() {
ExecutionManager executionManager = getSelfSchedulingRunnableExecutionManager();
executionManager.register("owner", "name", new SelfSchedulingRunnableTest());
}
@Override
public void unregisterSelfSchedulingRunnable() {
ExecutionManager executionManager = getSelfSchedulingRunnableExecutionManager();
executionManager.unRegister("owner", "name");
}
private static class SelfSchedulingRunnableTest implements SelfSchedulingRunnable {
private Instant nextScheduledTime;
private SchedulingController controller;
private Logger log = Logger.getLogger(SelfSchedulingRunnableTest.class);
@Override
public void run() {
Instant now = Instant.now();
log.info(String.format("SelfSchedulingRunnableTest running at: %s", now));
Instant nextMinute = now.truncatedTo(ChronoUnit.MINUTES).plus(Duration.ofMinutes(1));
nextScheduledTime = nextMinute;
controller.requestReschedule(this);
}
@Override
public void setController(SchedulingController controller) {
this.controller = controller;
}
@Override
public long getNextExecDelayMillis() {
if (isFirstRun()) {
return getInitialDelay();
} else {
return getNextDelay();
}
}
private boolean isFirstRun() {
return nextScheduledTime == null;
}
private long getInitialDelay() {
return Duration.ofSeconds(1).toMillis();
}
private long getNextDelay() {
Instant now = Instant.now();
if (nextScheduledTime.isAfter(now)) {
return nextScheduledTime.toEpochMilli() - now.toEpochMilli();
} else {
// This shouldn't happen under normal circumstances, but we don't want to return
// 0 or a negative number, because that signals Ignition not to reschedule
return 1;
}
}
}
Essentially I set things up so that I could call the register/unregister through RPC from the scripting console.
Below is an image showing an example session running this code. At some point between the logged data I ran unregister and watched the execution status page. Sure enough, the thread was removed from view. Once the turn of the minute came around, however, it ran again and added itself back into the map and continued to run every minute.
As a side question… I poked around the relevant SDK code and everything made sense to me in terms of the future being cancelled and stuff, but I could not debug due to line numbers not matching up. I am running 7.9.9 locally but I think my SDK version is set to 7.9.4 in Maven. Should I be able to set it to 7.9.9 and successfully debug into the Ignition code?
Thanks!