Cancel All Pending Tasks Question


#1

1) Give a description of the problem
I am seeking help with understanding the purpose of the “Cancel all Pending tasks” command. I’ve tried researching here but am unable to fully understand its purpose.

2) What is the expected behaviour?
I thought - from my research - that “Cancel all Pending Tasks” would mean that when a piston starts running, it kills off any instances of that same piston that is already running, but I am not sure now that is the case. Consider this case: I have a piston that seeks to get a refresh from a switch whenever a change is detected on the switch (the purpose of this was detailed in another post and is not exactly relevant here.) The switch is four-button, and it is not unusual for a user to press all four buttons on the switch, fractions of a second apart in between each button press… What I wanted to do is start a wait of 1 second, refresh, then wait 3 seconds, then get another refresh. But if a user presses all four buttons in rapid succession, then the first instance of the piston is killed by the second instance, which is then killed itself by the third instance, which is then in turn killed by the fourth instance of the piston, which would be the only one to really run in full. Thus I would avoid flooding the system with unnecessary refreshes, as I just wanted one or two at the very end.

3) What is happening/not happening?
I noticed during testing that all instances of the piston were running in succession, in parallel (because I enabled parallelism, otherwise the pistons would simply run in sequence and flood the system with refreshes just the same). The 1st, 2nd, and 3rd instances of the piston all run to completion.

What can I do to halt the execution of the 1st, 2nd, and 3rd instances by the most recent instance of that piston?

This is useful for me in a number of scenarios. E.g., motion activated lighting, where people are walking into and out of a room and you set a 3-minute timer for the light to switch off after a “No Motion” is registered, but you don’t want the piston to run to completion if a person/s continued walking into the room after that initial “No Motion” event, because the circumstances have since changed. So the ideal situation would be to once again start the piston that a) kills off the already running instance of that piston, b) switches on the light when it detects motion (light would already be on), and c) restart the 3-minute timer afresh. How does one go about this?

**4) Post a Green Snapshot of the piston![image|45x37]

5) Attach logs after turning logging level to Full
3/16/2021, 6:45:21 PM +221ms
+1ms ╔Received event [Dining Light 3].switch = on with a delay of 60ms
+54ms ║RunTime Analysis CS > 17ms > PS > 3ms > PE > 34ms > CE
+56ms ║Runtime (37897 bytes) successfully initialized in 3ms (v0.3.113.20210203) (54ms)
+57ms ║╔Execution stage started
+80ms ║║Comparison (enum) on changes = true (1ms)
+82ms ║║Condition #2 evaluated true (20ms)
+83ms ║║Condition group #1 evaluated true (state did not change) (21ms)
+85ms ║║Cancelling statement #46’s schedules…
+87ms ║║Executed virtual command cancelTasks (1ms)
+90ms ║║Cancelling statement #10’s schedules…
+93ms ║║Executed virtual command [Dining Light 1].wait (1ms)
+94ms ║║Waiting for 1000ms
+1213ms ║║Executed physical command [Dining Light 1].refresh() (116ms)
+1214ms ║║Executed [Dining Light 1].refresh (118ms)
+1218ms ║║Executed virtual command [Dining Light 1].wait (0ms)
+1219ms ║║Waiting for 3000ms
+4234ms ║║Executed physical command [Dining Light 1].refresh() (13ms)
+4235ms ║║Executed [Dining Light 1].refresh (15ms)
+4256ms ║╚Execution stage complete. (4199ms)
+4265ms ╚Event processed successfully (4265ms)
3/16/2021, 6:45:20 PM +163ms
+2ms ╔Received event [Dining Light 1].switch = on with a delay of 54ms
+51ms ║RunTime Analysis CS > 17ms > PS > 3ms > PE > 31ms > CE
+53ms ║Runtime (37897 bytes) successfully initialized in 3ms (v0.3.113.20210203) (51ms)
+54ms ║╔Execution stage started
+74ms ║║Comparison (enum) on changes = true (0ms)
+76ms ║║Condition #2 evaluated true (18ms)
+77ms ║║Condition group #1 evaluated true (state did not change) (19ms)
+79ms ║║Cancelling statement #46’s schedules…
+81ms ║║Executed virtual command cancelTasks (1ms)
+83ms ║║Cancelling statement #10’s schedules…
+87ms ║║Executed virtual command [Dining Light 1].wait (0ms)
+88ms ║║Waiting for 1000ms
+1195ms ║║Executed physical command [Dining Light 1].refresh() (104ms)
+1196ms ║║Executed [Dining Light 1].refresh (106ms)
+1199ms ║║Executed virtual command [Dining Light 1].wait (1ms)
+1200ms ║║Waiting for 3000ms
+4217ms ║║Executed physical command [Dining Light 1].refresh() (15ms)
+4218ms ║║Executed [Dining Light 1].refresh (17ms)
+4241ms ║╚Execution stage complete. (4186ms)
+4249ms ╚Event processed successfully (4249ms)

The above log represents two consecutive rapid button presses (less than a second apart) of 2 buttons on the same switch, which I thought would mean the piston fires twice, but the second would kill off the first one. Evidently, that did not happen.

Thnks in advance!


#2

Not that I want to reply to myself :slight_smile:

I did find this post: Cancel All Pending Tasks - Query and it is clear the guy was expecting the same thing I was - cancellation of anything waiting at a timer for that specific piston.

@bangali replied then:

So, why is this not happening in my case? Anyone, please?


#3

It appears to me the first piston execution continues to run, when the 2nd execution starts to run, so you have both running in parallel (and pretty much independently of each other).

The first execution really needs to go to sleep, which with 1 second waits, it just pauses.

So a way to test this better would be to start with longer waits in your tests, ones that cause the first piston to sleep and wakeup on a timer.

You may also need to enable parallel execution so the pistons use atomicState more, but I still think the short waits are biting you.


#4

Thank you for the response… You might be right. I will test and get back to you on here…

What is a long enough wait that forces the execution to go to sleep? More than 10 seconds?

Parallel execution is already enabled (as in the above piston)… So that part is fine. It’s likely more about the length of the wait as you said. I do not really know what atomicState is and will look that up.

Thank you!


#5

I do believe you were right… I tried this with a wait of 5 seconds instead of 1 or 3 seconds, and I can see in the log that a “wake up was scheduled”… And after pressing 2 buttons in rapid succession on the same switch, the piston fired once for each button, but it appears that the actions scheduled by the first piston never woke up and were therefore cancelled - though this was not very obvious from the log (I would have like to see that a scheduled wake-up was cancelled to be 100% certain).

So, thank you, I think the short wait was biting me, as you said… Credit also to @orangebucket who was also pointing in this direction in a different post though I might not have understood what he meant, now things are clearer, so thanks to both!