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
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