DOTS Deep Dive 2: Cancel me or I will crash your server...
One of our slides in the recent DOTS session in IBM Connect 2013, we have talked about the "monitor" argument in tasklets. It has two important uses.
First of all, you might let DOTS container know about your progress. Second, it allows you to cancel your task in a less-disruptive manner.
Let's dive into code here.
Our tasklet is running every five seconds and wait 30 seconds each run:
@RunEvery( every=5, unit=RunUnit.second )
public void run5(IProgressMonitor monitor) throws Exception {
logMessage("START: 5 Secs");
monitor.beginTask("Sleeping well", 15);
for(int i=0; i<15; i++) {
monitor.worked(1);
Thread.sleep(2000);
}
logMessage("END: 5 secs");
}
We have splitted 30 seconds wait into 15 parts of sleeping to make more sense. Using "beginTask" method at start, we have declared that "Our tasklet will do 15 units of job". Each unit, we inform progress monitor for "1 unit completed" message with "worked" method. We can check the status from the console:
11.02.2013 12:22:03 [DOTS] (stest01) START: 5 Secs
> tell dots taskstatus
11.02.2013 12:22:06 [DOTS] Display the list of OSGi tasklets currently in progress
11.02.2013 12:22:06 [DOTS] Scheduled Runs
11.02.2013 12:22:06 [DOTS] --- stest01 [Sleeping well] (13,333%)
11.02.2013 12:22:06 [DOTS] Triggered Runs
11.02.2013 12:22:06 [DOTS] --- No task running
11.02.2013 12:22:06 [DOTS] Manual Runs
11.02.2013 12:22:06 [DOTS] --- No task running
What if we cancel this task? Lets try...
11.02.2013 12:28:58 [DOTS] (stest01) START: 5 Secs
> tell dots q
11.02.2013 12:29:02 [DOTS] Canceling task stest01
11.02.2013 12:29:29 [DOTS] (stest01) END: 5 secs
11.02.2013 12:29:29 Domino OSGi Tasklet Container terminated ( profile DOTS )
When we stop DOTS task, it will try to cancel our task. However it's not a cancellation. Our tasklet finished its run (30 seconds) because it doesn't have an idea we have sent a cancel signal...
Now add a simple check inside our loop...
@RunEvery( every=5, unit=RunUnit.second )
public void run5(IProgressMonitor monitor) throws Exception {
logMessage("START: 5 Secs");
monitor.beginTask("Sleeping well", 15);
for(int i=0; i<15; i++) {
monitor.worked(1);
Thread.sleep(2000);
if(monitor.isCanceled()) {
logMessage("Cancel request taken...");
break;
}
}
logMessage("END: 5 secs");
}
When we cancel the tasklet, it will get the signal and break the execution...
11.02.2013 12:34:29 [DOTS] (stest01) START: 5 Secs
> tell dots q
11.02.2013 12:34:32 [DOTS] Canceling task stest01
11.02.2013 12:34:33 [DOTS] (stest01) Cancel request taken...
11.02.2013 12:34:33 [DOTS] (stest01) END: 5 secs
11.02.2013 12:34:34 Domino OSGi Tasklet Container terminated ( profile DOTS )
Receiving the cancel signal is extremely important. Suppose you are developing a very very long-running tasklet (it might be a manual tasklet as well). You should be able to break the execution at any point without waiting its normal run. At some point of cancellation, DOTS will decide it's crashed and fill your console with strange error messages...
One last point: Cancellation can be achived by "tell dots cancel (tasknumber)" command. I couldn't find out what the tasknumber is but if you don't provide a parameter, it will cancel all running tasks at once.
Comments (6)
OK, I found out why. To cancel a specific task, as article you wrote says, the task ID is required, which has to be a number.
I decompiled the offended class and found this:
[code]/* */ public int cancelTask(String paramString)
/* */ {
/* 300 */ int i = Integer.valueOf(paramString).intValue();
/* 301 */ synchronized (this.runningServiceTaskJobs) {
/* 302 */ for (ServiceTaskJob localServiceTaskJob : this.runningServiceTaskJobs) {
/* 303 */ if (localServiceTaskJob.jobId == i) {
/* 304 */ localServiceTaskJob.cancel();
/* 305 */ return 1;
/* */ }
/* */ }
/* */ }
/* 309 */ return 0;
/* */ }[/code]
At the 300th row a String to int transformation is happening.
To find out what the task number is I went through the dots commands:
> tell dots taskstatus
05/08/2014 11:04:05 AM [DOTS] Display the list of OSGi tasklets currently in progress
05/08/2014 11:04:05 AM [DOTS] Scheduled Runs
05/08/2014 11:04:05 AM [DOTS] --- No task running
05/08/2014 11:04:05 AM [DOTS] Triggered Runs
05/08/2014 11:04:05 AM [DOTS] --- No task running
05/08/2014 11:04:05 AM [DOTS] Manual Runs
05/08/2014 11:04:05 AM [DOTS] --- (2) Contact.gogogo@run5 [Sleeping well] (40%)
05/08/2014 11:04:11 AM Remote console command issued by Shillem Volpato/MTK: tell dots cancel 2
there you go. the task number is 2. And now I can cancel it
> tell dots cancel 2
05/08/2014 11:04:12 AM [DOTS] Canceling task 2...
There only remains a problem. Using the general cancel without parameter won't do it. It should cancel all tasks but it doesn't and triggers the problem. It's a bug, isn't?
I'm checking this out thing but if I use the cancel command - with and without specifying the task - it always throws an exception and the task doesn't get canceled. It only works if I quit the DOTS task entirely. Any ideas why? I'm running Domino + OpenSocial Component 9.0.1FP1
05/08/2014 10:18:43 AM Remote console command issued by Shillem Volpato/MTK: tell dots cancel Contact.gogogo
05/08/2014 10:18:44 AM [DOTS] Canceling task Contact.gogogo...
05/08/2014 10:18:44 AM [DOTS] A Java Exception occurred: java.lang.reflect.InvocationTargetException
05/08/2014 10:18:44 AM [DOTS] java.lang.reflect.InvocationTargetException
05/08/2014 10:18:44 AM [DOTS] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
05/08/2014 10:18:44 AM [DOTS] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
05/08/2014 10:18:44 AM [DOTS] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
05/08/2014 10:18:44 AM [DOTS] at java.lang.reflect.Method.invoke(Method.java:611)
05/08/2014 10:18:44 AM [DOTS] at com.ibm.dots.internal.OSGIConsoleAdaptor.runCommand(OSGIConsoleAdaptor.java:288)
05/08/2014 10:18:44 AM [DOTS] at com.ibm.dots.task.ServerTaskManager._processCommand(ServerTaskManager.java:669)
05/08/2014 10:18:44 AM [DOTS] at com.ibm.dots.task.ServerTaskManager.processCommand(ServerTaskManager.java:630)
05/08/2014 10:18:44 AM [DOTS] Caused by: java.lang.NumberFormatException: For input string: "Contact.gogogo"
05/08/2014 10:18:44 AM [DOTS] at java.lang.NumberFormatException.forInputString(NumberFormatException.java:59)
05/08/2014 10:18:44 AM [DOTS] at java.lang.Integer.parseInt(Integer.java:460)
05/08/2014 10:18:44 AM [DOTS] at java.lang.Integer.valueOf(Integer.java:565)
05/08/2014 10:18:44 AM [DOTS] at com.ibm.dots.task.JobTaskService.cancelTask(JobTaskService.java:300)
05/08/2014 10:18:44 AM [DOTS] at com.ibm.dots.task.ServerTaskManager.cancelTask(ServerTaskManager.java:967)
05/08/2014 10:18:44 AM [DOTS] at com.ibm.dots.Activator._cancel(Activator.java:212)
05/08/2014 10:18:44 AM [DOTS] ... 7 more
There is an intermittent problem with that abort process. When I find the exact problem, I will blog about it.
Shillem, as you already found out, it fails if you provide a non-integer string.
About cancel command without parameter, it is working as of 9.0 (didn't test it with a later version). Did you test it with scheduled tasklets as well? In the next post ({ Link } ) I'm canceling scheduled tasklets with cancel command.
Maybe it's a problem of manual tasklets. Source has not been changed much, so you can look at the source code on the OpenNTF project. There is com.ibm.dots.task.ServerTaskManager class containing cancelTask and cancellAllTasks methods.