Hi Ben

I completely agree with you on point two. The semantics I'm trying to get
at for point one are a bit different. Events are information that is
relevant for a single point in time, not until the information is
processed. *Events can be processed by multiple handlers or by none, and in
both cases they become irrelevant after the single point in time.*

Take the 'file_changed' event for example. A great use for this is to
restart a service when a file changes. Take the following code:

@file_changed('xyz')
@when(service.started)
def restart():
    ...

If the service is started at the time the 'file_changed' event fires, this
handler should be queued. While the handler is queued, only the state
should be retested, not the event. If the service stops while this handler
is queued, the handler should be dropped from the queue. Multiple handlers
can react to this event, or none, but in all cases, the event should become
inactive after the initial queuing of handlers (the single point in time).
If the `file_changed` event fires and the service is not started, this
handler should not be queued. If the service starts after the event fires,
this handler should not get executed.

So what I'm getting at is this:

 - Handlers with event decorators may only be queued immediately after the
event has fired
 - Events do not get retested in the queue
 - States work as they do now

One of the problems with 'Information that is relevant till processed.' is
that it is almost impossible for the framework to know when an event is
'processed'. Because of this, the current implementation of `file_changed`
is buggy <https://github.com/juju-solutions/charms.reactive/issues/44>.
Moreover, it is common for events to not get processed at all. For example
when the file changes while the service is stopped.

I do see the importance of this being fault-tolerant. The reactive
framework is currently not fault tolerant
<https://github.com/juju-solutions/charms.reactive/issues/38> and can has
different behavior in case of failure depending on whether a handler is
internal or external. One of the ways we could achieve some level of
fault-tolerant events is by remembering both the queue and the states when
a handler fails. Even without events, *I think remembering the queue on
failure is a good thing to do. I think it would enable a powerful debugging
workflow.*



PS: I'm interested to hear more about making applications model aware!

2016-02-18 18:42 GMT+01:00 Benjamin Saller <benjamin.sal...@canonical.com>:

> I really appreciate this kind of thinking, looking for root causes is the
> hallmark of better systems design. That said I'd suggest the difference
> between _event_ and _state_ as you describe them are really only a usage
> convention around the same abstraction.
>
> The semantics you seem to be pointing towards are:
>
>      1. Information that is relevant till processed.
>       2. Information that acts as a fact, persistent knowledge of the
> system.
>
> Point two is how you see states today. Point two states are only
> persistent facts until something changes that makes us re-evaluate them,
> this how ever is also true of point 1. In the case of point 1 processed
> means the state indicated by the system has been included into the
> applications model of the world and no longer needs to be considered. In
> examples like that we set the state and clear it when the expected changes
> have been applied. The lifetime of the state doesn't change its
> abstraction.
>
> Another way of look at these two things with an eye towards unifying them
> in our understanding is to think about how they are handled in the event of
> failure. From programmer error to random entropy (sun spots) when the
> execution stops the "event" or "state" must still be handled in a
> subsequent invocation for the unit to be in a proper state. This alone
> blurs the line between your two ideas. States try to make "Fire and forget"
> work even in the case of failure by saying that code paths impacted by this
> state should continue to trigger until the charm indicates otherwise
> (ending in a later success state).
>
>
> -Ben
>
> PS. As far as treating the reactive system like a daemon and having the
> ability to connect to external event sources, that is interesting and syncs
> well with something I am currently working on, but does so by making
> applications model aware rather than by trying to make the charms of today
> more deeply integrated into the applications they manage.
>
>
> On Thu, Feb 18, 2016 at 2:06 AM Merlijn Sebrechts <
> merlijn.sebrec...@gmail.com> wrote:
>
>> I sort of agree that it feels wrong to lump configuration change events
>> into states. That said, adding another primitive doesn't seem like a good
>> idea. The primitive doesn't nearly cover all cases. I think the problem
>> with `x.changed` states is just a symptom, and we should address the root
>> cause, not the symptoms.
>>
>> *The root cause seems to me that there is no distinction between `states`
>> and `events`.* A state such as `package.installed` is a fact. It will
>> stay true until something manually removes the state. `config.changed` is
>> not a state but an event. An event is only relevant at a single point in
>> time, after that timepoint, the event gets removed. `file_changed` and
>> `config_changed` are events that are only relevant in a single point of
>> time.
>>
>> The reason that the `config_changed` event is relevant during an entire
>> hook run is because hooks do not run in "real external time" but in an
>> external timepoint. When an outside event happens during a hook run, the
>> events get queued, and the next event is handled after the hook run is
>> complete. A simple example is the stop hook; this can be seen as a
>> `stop.requested` event. When a `config-changed` hook is running and an
>> administrator destroys the service, the `stop` hook will only run after the
>> `config-changed` hook is complete.
>>
>> Some advantages of introducing the concept of events:
>>
>> - It will be a lot clearer for devs that events get removed after a
>> certain period of time and that states stay in the knowledgebase. Currently
>> certain layers remove certain states at the start of a hook run; I think
>> this can become very confusing for devs.
>>
>> - It would give us a clear 'logic' that tells us how to implement things
>> like the 'file_changed' decorator. There are currently some issues with
>> this: https://github.com/juju-solutions/charms.reactive/issues/44
>>
>> - The connection between the reactive framework and the lifecycle(hooks)
>> would be a lot clearer. Each hook is an external event; external events
>> aren't processed in real-time; ...
>>
>> - This would pave the way for Charms to react to other events such as
>> systemd dbus events as mgmt does:
>> https://ttboj.wordpress.com/2016/01/18/next-generation-configuration-mgmt/.
>> Imagine being able to run a hook when a systemd service crashes or when
>> files change outside of a hook run!
>>
>>
>> So, what do you think? This is hard to explain in a single email and I
>> left a lot of the details out, so feel free to ask for more clarification!
>>
>>
>>
>> 2016-02-17 23:55 GMT+01:00 Matt Bruzek <matthew.bru...@canonical.com>:
>>
>>> I hate to go against the love-in here. While I desperately want a
>>> configuration changed feature for the reactive framework. I disagree with
>>> the way it was implemented. I brought up issues with this implementation in
>>> the pull request:  https://github.com/juju-solutions/layer-basic/pull/36
>>>
>>> It feels wrong to lump configuration change events in to states. There
>>> should be a different way to handle these types of events that are
>>> generated by Juju. We already have @hook('config-changed') for when the
>>> traditional hook would be called. When a configuration changes it would be
>>> more natural should have a different decorator for that such as:
>>> @when_changed('key') or more importantly
>>> @when_any_changed('key1','key2','key3')
>>>
>>> Charm states are completely arbitrary and an author (who may not read
>>> this list) could legitimately set a 'config.changed' state that would
>>> create invalid changed events and break other layers. Even if we pick a
>>> different state name it seems we are inviting a possible collision that
>>> would be very difficult to diagnose and debug.
>>>
>>> It feels strange that we are "reserving" a state name (or many names)
>>> for the configuration changes in this way. Implementing the feature with a
>>> different decorator seems more deterministic and not overloading the states
>>> with configuration events.
>>>
>>> Thoughts?
>>>
>>>    - Matt Bruzek <matthew.bru...@canonical.com>
>>>
>>> On Wed, Feb 17, 2016 at 4:00 PM, Merlijn Sebrechts <
>>> merlijn.sebrec...@gmail.com> wrote:
>>>
>>>> Great! Very usefull! Thanks, Cory!
>>>>
>>>>
>>>> Op woensdag 17 februari 2016 heeft Cory Johns <cory.jo...@canonical.com>
>>>> het volgende geschreven:
>>>> > Just wanted to give a heads-up about a feature that landed in the
>>>> reactive base layer yesterday.
>>>> > If a charm config option has changed, the state "config.changed" will
>>>> be set for the duration of the hook.  Additionally, specific states will be
>>>> set for each config option that changed; that is, if option "foo" has
>>>> changed, the state "config.changed.foo" will be set.  An example of code
>>>> using this would be:
>>>> >     @when('myservice.started', 'config.changed')
>>>> >     def update_config():
>>>> >         update_config_files()
>>>> >         restart_myservice()
>>>> > This provides a much cleaner way of detecting changes to config, and
>>>> it is recommended that this be used in favor of @hook('config-changed')
>>>> going forward, as the latter can actually run in to some situations, albeit
>>>> rather rarely, where the charm sees new config option values before the
>>>> config-changed hook has fired.  Using the reactive states avoids that
>>>> completely as well as working more naturally with existing @when 
>>>> decorators.
>>>> > Please note that, while we are not aware of any charms currently
>>>> using "config.changed" as a state, there is some risk of the state set by
>>>> the base layer conflicting with it if set by the charm layer.  The
>>>> recommendation is to always prefix your states by the name of the layer
>>>> setting them,  or the relation name for interface layers.
>>>>
>>>> --
>>>> Juju mailing list
>>>> Juju@lists.ubuntu.com
>>>> Modify settings or unsubscribe at:
>>>> https://lists.ubuntu.com/mailman/listinfo/juju
>>>>
>>>>
>>>
>>
-- 
Juju mailing list
Juju@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju

Reply via email to