Help understanding state changes and cancellation policy


#1

I’m watching a thread on Facebook where someone is looking for support on a fairly straight forward piston. I don’t want to post someone else’s piston, so I’ll just describe it which should be enough.

If momentary button tile switch changes to on:
with device:
Turn off.
wait 5 seconds
command()

The user is explaining that it only works “half the time”.

I can see in the logs they’ve posted, quite clearly, that "Comparison (enum) on changes_to (string) on = true… and then the remaining tasks are being cancelled.

Now, I understand enough of WebCore to understand how the wait command is handled in regards to cancellation in that a change in the parent conditions state will cancel pending actions by default… but why is it only happening “half of the time”? I’m guessing it has to do with it being a momentary button tile, and that the changes to on then immediately after changes to off may be what’s causing it? If that’s the case, why is it only happening sometimes? Can someone explain what’s happening here?

Log story short, I think the “fix” here is to change the cancelation policy to never cancel… but I’d like to better understand the mechanics here involve for my own benefit.

Thank you.


#2

Just shooting blind here:)

For a 5 second wait (without Never Cancel Task)
it might even be a simple signal and timing issue.

I would recommend changing 5 seconds to 20 seconds and see if still works “half the time”


#3

I’m pretty certain it is a timing issue as the logs where the piston is working is showing that its executing about 10ms faster than the one that’s failing… but that is well short of 5 seconds. Does this make sense:
Good
0ms button is pushed
100ms step one executes
110ms button is released
120ms wait command checks button state, = off
…sleep
5120ms …wakes up, checks button state, = off
5130ms… last step executes

Bad:
0ms button is pushed
100ms step one executes
120ms wait command checks button state, = on (button hasn’t bee released yet)
…sleep
121ms button is released
5120ms …wakes up, checks button state, = off
State has changed, pending tasks are cancelled

In the good state the button has released before the wait evaluates the state of the condition, off and its still off when the sleep is over = tasks continue

in the bad state, due to timing, the button hadn’t yet turned off when the wait evaluated with the state was, at the time is was still “on” when the wait ended and it reevaluated, the switch had turned to off… it intrepreted it as a state change and cancelled execution


#4

To avoid timing issues,
on button press --> set variable to true

Then second string

If variable = true
Turn device off
Wait 5 seconds
Command()
Set variable to false


#5

If the wait is set to 20 seconds, it should fail every time…
If the wait is set to 1 second, it should work every time…

It is the 3-5 second window that can go either way, since technically, after the wait, the momentary button did not change to on.

It can be tweaked by changing the cancellation policy.


#6

I don’t understand this part of it… what is the significance of 3-5 seconds?


#7

I assume in version 1.0 of webCoRE that your original piston would fail at any wait whatsoever… It would make sense for ady to have added a safety net (a delay) so the event would still be true a few moments later. Most of my observations have seen this point in time around the 4 second mark, but sometimes a 3 second wait will fail, and sometimes, a 5 second wait will succeed.

This is why I said within a window of approximately 3-5 seconds, the results will be inconsistent unless the Task Cancellation Policy has been changed.


Basically, really short waits will still show the trigger as being true, and longer waits will show the trigger as no longer true. 3-5 seconds seems to be the transitory point between those two.


#8

To see it in action:

Here is a sample piston I made with a 5 second wait…

5sec

(All commands executed perfectly)


Here is the exact same piston with the wait at 6 seconds…

6sec

(It only runs the first command and the final command located outside the IF)