Is a set state called multiple times?

Alex Kavanagh alex.kavanagh at canonical.com
Fri Jul 28 09:37:29 UTC 2017


Hi fengxia

As Cory says, it's much better to think of the set_state() and
remove_state() as binary flags; in fact in the upcoming version, set_state
becomes set_flag() and remove_state() becomes remove_flag()  -- although
the existing functions will still exist for backwards compatibility.

So a handler with a set of conditions built from flags (states) that
evaluates to 'true' will always run on EVERY invocation of the charm;
that's all of the charm hooks, plus relation hooks.

This can often lead to a charm 'doing too much' during a hook invocation if
you don't gate or otherwise detect that a charm doesn't need to do
something.  I've had 'bugs' in the past where databases were set up
multiple times because I didn't gate (by using a flag/state) the 'have I
set up the database yet'.  Just something to watch for.

Also, the update-status hook is a bit redundant now.  To get equivalent
functionality without having to use a @hook('update-status') just use a
@when_not("never-set-update-status") and it will always run on every hook
invocation; it also means you can gate the 'update status' if certain other
things haven't happened.

And yes, in your example, you can use flags to 'make progress' in the charm
life-cycle by using them to only run a bit of functionality once.  You can
always do them in cycles too!

Finally, remember that states are NOT shared amongst units of the same
application; they are unique to each individual unit.  Juju is not aware
that the charm is using reactive states.

Hope this helps
Cheers
Alex.


On Thu, Jul 27, 2017 at 9:09 PM, fengxia <fxia1 at lenovo.com> wrote:

> Now thinking of it, I just realized that this concept of True state
> executing repeatedly is actually a good thing.
>
>
> In many cases, there is a need to query external resource for its status.
> This is often implemented as a polling loop. So in charm, I can implement
> it as
>
>
> @when("prep")
>
> def prep():
>
>     # are we there yet?
>
>     is_ready = prep_test()
>
>     if is_ready:
>
>         remove_state("prep")
>
>         set_state("do.sth")
>
> @when("do.sth")
>
> def do_sth():
>
>     # do this
>
>     pass
>
>
>     # move on
>
>     remove_state("do.sth")
>
>     set_state("next")
>
> On 07/27/2017 03:56 PM, Cory Johns wrote:
>
> fengxia,
>
> It's probably more enlightening to think of them as "flags" rather than
> states.  (Indeed, the next release of charms.reactive will deprecate
> calling them states and will provide set_flag, remove_flag, etc. functions
> instead.)
>
> On Thu, Jul 27, 2017 at 3:29 PM, fengxia <fxia1 at lenovo.com> wrote:
>
>> Alex,
>>
>> Thank you for the detailed explanations and examples.
>>
>> After reading Tilman's and Cory's replies, I think the confusion is at
>> continuous evaluation (thus execution) of a True state. So a pair of @when
>> and @when_not will result in one of them being executed over and over
>> despite adding a remove_state("myself") in the @when block.
>>
>> I'm still trying to grasp the idea of this "state" instead of treating it
>> as an event handler.
>>
>> So for states, I usually draw a state machine diagram. In this case, it
>> feels rather unnatural that all True states will inherently loop to
>> themselves.
>>
>> But I don't what alternative is in charm's context.
>>
>> On 07/27/2017 04:13 AM, Alex Kavanagh wrote:
>>
>> Hi
>>
>> On Thu, Jul 27, 2017 at 2:37 AM, fengxia <fxia1 at lenovo.com> wrote:
>>
>>> Hi Juju,
>>>
>>> Once I set a state, set_state("here"), I want to make sure its @when
>>> will only be executed ONCE (when "here" from False->True).
>>>
>>> So my thought is to remove_state("here") in its @when("here") code
>>> block. If I don't, will this @when be called multiple times if I don't
>>> reset this state? What's the good practice here?
>>
>>
>> You have a couple of options here depending on the nature of the handler.
>>
>>
>>    1. If, in the lifetime of the unit's existence, the handler only has
>>    to execute ONCE.  (and I mean EVER), then there is a @only_once decorator
>>    that can be used.  It can be used in combination with other decorators to
>>    set up a condition, but it guarantees that the handler will only be called
>>    once.  However, what you probably want is ...
>>    2. Use a @when_not('flag') and then set it the 'flag' in the body of
>>    the handler.
>>
>> The first would look something like:
>>
>> @when('some-condition-flag')
>> @only_once
>> def do_something_only_once_when_some_condition_flag_is_set_for_
>> the_first_time():
>>      ... do something once ...
>>
>> The second treats a flag as a 'have I done this yet' condition, and
>> allows you to reset the flag at some other point in the charm's life cycle
>> so that you can do it again.  'installed' is a good example of this:
>>
>> @when_not('installed-something')
>> def do_install_of_something():
>>     ... do the installation ...
>>     # when it is fully successful, set the installed-something flag.
>> Don't set it early as
>>     # if it errors, a future handler invocation may be able to continue
>> the installation.
>>     set_state('installed-something')
>>
>>
>> @when(some other conditions indicating do an upgrade)
>> def do_upgrade():
>>      ... set upgrade sources, or other pre upgrade actions
>>      remove_state('installed-something')
>>
>> In this situation, hopefully you can see that we can re-use
>> 'do_install_of_something()' when we do upgrades.
>>
>> I think it's useful to think about states (flags) as being a 'memory'
>> that something has happened, and use them to either gate on not doing
>> things again, or to trigger the next action is a graph of actions that need
>> to take place to get the charm's payload to the desired operational state.
>> I tend to name them, and use them, to indicate when something has happened,
>> rather than when it hasn't, and so tend to use @when_not('some-flag') on
>> the handler that eventually sets that flag.
>>
>> Hope that this helps.
>> Alex.
>>
>>>
>>>
>>> --
>>> Feng xia
>>> Engineer
>>> Lenovo USA
>>>
>>> Phone: 5088011794
>>> fxia1 at lenovo.com
>>>
>>> Lenovo.com
>>> Twitter | Facebook | Instagram | Blogs | Forums
>>>
>>>
>>> --
>>> Juju mailing list
>>> Juju at lists.ubuntu.com
>>> Modify settings or unsubscribe at: https://lists.ubuntu.com/mailm
>>> an/listinfo/juju
>>>
>>
>>
>>
>> --
>> Alex Kavanagh - Software Engineer
>> Cloud Dev Ops - Solutions & Product Engineering - Canonical Ltd
>>
>>
>> --
>> Feng xia
>> Engineer
>> Lenovo USA
>>
>> Phone: 5088011794 <%28508%29%20801-1794>fxia1 at lenovo.com
>>  	
>> Lenovo.com
>> Twitter | Facebook | Instagram | Blogs | Forums
>>
>>
>> --
>> Juju mailing list
>> Juju at lists.ubuntu.com
>> Modify settings or unsubscribe at: https://lists.ubuntu.com/mailm
>> an/listinfo/juju
>>
>>
>
>
>
> --
> Feng xia
> Engineer
> Lenovo USA
>
> Phone: 5088011794 <(508)%20801-1794>fxia1 at lenovo.com
>  	
> Lenovo.com
> Twitter | Facebook | Instagram | Blogs | Forums
>
>
> --
> Juju mailing list
> Juju at lists.ubuntu.com
> Modify settings or unsubscribe at: https://lists.ubuntu.com/
> mailman/listinfo/juju
>
>


-- 
Alex Kavanagh - Software Engineer
Cloud Dev Ops - Solutions & Product Engineering - Canonical Ltd
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ubuntu.com/archives/juju/attachments/20170728/1ce1757f/attachment.html>


More information about the Juju mailing list