Very helpful indeed! Thank you for the insight Alex.

The concern of "doing too much" is exactly what started conversation when we are expecrimenting with charm, because in our design we are using charm as a state-driven framework that interacts with external resources. So it's the sanity of these external resources we want to guard.



On 07/28/2017 05:37 AM, Alex Kavanagh wrote:
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 <fx...@lenovo.com <mailto:fx...@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 <fx...@lenovo.com
    <mailto:fx...@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 <fx...@lenovo.com
        <mailto:fx...@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 <tel:5088011794>
            fx...@lenovo.com <mailto:fx...@lenovo.com>

            Lenovo.com
            Twitter | Facebook | Instagram | Blogs | Forums


-- Juju mailing list
            Juju@lists.ubuntu.com <mailto:Juju@lists.ubuntu.com>
            Modify settings or unsubscribe at:
            https://lists.ubuntu.com/mailman/listinfo/juju
            <https://lists.ubuntu.com/mailman/listinfo/juju>




-- Alex Kavanagh - Software Engineer
        Cloud Dev Ops - Solutions & Product Engineering - Canonical Ltd

-- Feng xia
        Engineer
        Lenovo USA

        Phone:5088011794 <tel:%28508%29%20801-1794>
        fx...@lenovo.com <mailto:fx...@lenovo.com>
                
        Lenovo.com
        Twitter | Facebook | Instagram | Blogs | Forums


        --
        Juju mailing list
        Juju@lists.ubuntu.com <mailto:Juju@lists.ubuntu.com>
        Modify settings or unsubscribe at:
        https://lists.ubuntu.com/mailman/listinfo/juju
        <https://lists.ubuntu.com/mailman/listinfo/juju>





-- Feng xia
    Engineer
    Lenovo USA

    Phone:5088011794 <tel:%28508%29%20801-1794>
    fx...@lenovo.com <mailto:fx...@lenovo.com>
        
    Lenovo.com
    Twitter | Facebook | Instagram | Blogs | Forums


    --
    Juju mailing list
    Juju@lists.ubuntu.com <mailto:Juju@lists.ubuntu.com>
    Modify settings or unsubscribe at:
    https://lists.ubuntu.com/mailman/listinfo/juju
    <https://lists.ubuntu.com/mailman/listinfo/juju>




--
Alex Kavanagh - Software Engineer
Cloud Dev Ops - Solutions & Product Engineering - Canonical Ltd

--
Feng xia
Engineer
Lenovo USA

Phone: 5088011794
fx...@lenovo.com
        
Lenovo.com
Twitter | Facebook | Instagram | Blogs | Forums

-- 
Juju mailing list
Juju@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju

Reply via email to