<div dir="ltr">So the best practice here is to touch a file and test for the existence of that file before running must_be_called_exactly_once()?<div><br></div><div>I think part of the issue here is that without knowing the extent of the hook it is hard to enforce idempotency as a charm writer. It's easy to look at the code above and say that is it idempotent since the init function is wrapped in a when_not and the initialized state is set at the bottom of init.</div></div><br><div class="gmail_quote"><div dir="ltr">On Tue, Oct 3, 2017 at 1:43 PM Alex Kavanagh <<a href="mailto:alex.kavanagh@canonical.com">alex.kavanagh@canonical.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hi there<div><br></div><div><br></div><div class="gmail_extra"><br><div class="gmail_quote"></div></div></div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Tue, Oct 3, 2017 at 1:34 PM, Konstantinos Tsakalozos <span dir="ltr"><<a href="mailto:kos.tsakalozos@canonical.com" target="_blank">kos.tsakalozos@canonical.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div>Hi,</div><div><br></div><div>It seems the reactive framework is flushing the states at the end of hook execution. This may surprise charm authors. Consider the following code:</div><div><br></div><div>@when_not("initialized")</div><div>def <span id="m_3013255123506364600m_-8791093494745867110:1t0.2">init</span>():</div><div>    must_be_called_exactly_once()<br></div><div>    set_state("initialized")<br></div><div><br></div><div>@when("initialized")</div><div><div>@when_not("ready")</div></div><div>def get_ready():<br></div><div>    this_call_fails()</div><div>    set_state("ready")</div><div><br></div><div>As a charm author I would expect the "initialized" state set right after the must_be_called_exactly_once() is called. However, the framework is not persisting the "initialized" state at that point, and it moves on to trigger the get_ready(). Since this_call_fails() happens on the  get_ready() method I would expect the "initialized" state to be set when the failure is resolved.</div><div><br></div></div></blockquote><div><br></div></div></div></div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>Yup, that can catch you out.  As Stuart says, it's because either a hook competes 'fully' or not at all, and so it rolls back (or rather doesn't commit) the kv() store.  So anything you put in kv() (from charmhelpers.core.unitdata) also won't get committed.   Also, if you flush kv() yourself you'll mess with charms.reactive.</div><div><br></div><div>In this situation, I tend to use a file as a sentinel to flag that I've really done something only once.  Alternatively, one could use charmhelpers.core.unitdata.Storage() directly and thus flush a separate Storage() back to the 'disk'.</div></div></div></div><div dir="ltr"><div class="gmail_extra"><br><br clear="all"><div><br></div>-- <br><div class="m_3013255123506364600gmail_signature" data-smartmail="gmail_signature"><div dir="ltr">Alex Kavanagh - Software Engineer<div>Cloud Dev Ops - Solutions & Product Engineering - Canonical Ltd</div></div></div>
</div></div>
--<br>
Juju mailing list<br>
<a href="mailto:Juju@lists.ubuntu.com" target="_blank">Juju@lists.ubuntu.com</a><br>
Modify settings or unsubscribe at: <a href="https://lists.ubuntu.com/mailman/listinfo/juju" rel="noreferrer" target="_blank">https://lists.ubuntu.com/mailman/listinfo/juju</a><br>
</blockquote></div>