Discussion on hooks: relation-departed and relation-broken


#1

I’m seeking clarification and discussion on the hooks relation-departed and relation-broken. This surfaced as a documentation issue at the beginning of the year.


Apparently one can still do relation_set once -relation-departed is run but how will the other side react to that to read this new relation data? Will it receive another -relation-changed event or not? It is not clear at all.

What are the ordering guarantees for relation-departed in this case?

To make use of relation_set in -departed more information is needed. If there are two applications A and B in would be useful to know what happens after Juju remove-relation A B:

  1. Do all units in A get a chance to run relation-departed before all units in B? Or there is no order to that?
  2. Can relation-set be used on all A and B units? How will they receive relation data updates before -relation-broken?
  3. Is there a guarantee that no -broken event will be triggered while there are still -departed events to be processed on individual units of A or B?

It would make sense to me if something like that was described:

  1. Any A or B unit can do relation_set in -relation-departed
    OR relation_set cannot be used in -relation-departed;
  2. Any A or B unit can do relation_get in -relation-broken to retrieve settings set in -relation-departed
    OR relation_get and relation_set cannot be used in -relation-broken
    OR there is no way to do a relation_set after -relation-departed

I think it is a valid use-case to send some data over a relation after an operator runs remove-relation because there may be some information needed on A or B units from the other side for proper cleanup besides the information already present on a given relation when -relation-departed fires.


#2

One somewhat subtle consideration of how relations work in Juju that I find helpful when thinking about these things is that, while we like to think of relations “sending” data across the wire, it’s really more about each unit “publishing” their own set of data. So, a unit can continue to call relation-set as long as it has a valid relation ID, even if there are no units on the other side of the relation. If you are using the Endpoint base for interface layers, this is made more clear by the fact that you have to use the to_publish collection on a Relation instance to publish data for the other side to see.

As for the hook execution for relation hooks, let’s consider we have two applications, a and b, with two units each, a/1, a/2, b/1, and b/2, which are related together.

Let’s say we call juju remove-unit b/2. What will happen is the relation-departed hook will run on each affected unit, in no particular order: a/1, a/2, and b/2. During these hooks, all units will still be able to see all other units, and any unit can call relation-set to update their own published set of data on the relation. After this, b/2 will get the relation-broken hook (only b/2 will get this hook, because it’s the only unit leaving the relation scope), followed by the stop hook, and then be shut down. If any of the a units publish new data on the relation during the relation-departed hooks, b/1 will have relation-changed hooks triggered and will see the new data, but b/2 will never see it. If b/2 calls relation-set during the relation-departed hook, I think it is essentially just ignored.

Let’s say we now call juju remove-unit b/1. This proceeds identically to the previous case: relation-departed called for a/1, a/2, and b/1, while relation-broken and stop are called only on b/1. Again, no relation-broken hooks will be triggered on any of the a units, because there is still technically an established relation which a/1 and a/2 are a part of, even though the b application has no units. Only if the relation itself is removed via juju remove-relation will a/1 and a/2 receive the relation-broken hook. As mentioned previously, either unit of a can call relation-set at any time after this to publish new data (it will need to explicitly provide the relation ID, but that’s good practice anyway), even though there are no units on the other side of the relation to be notified of the change.

Long story short, if there is information that a or b will need from the other side to clean up after the relation is broken, you will need to send that info while the relation is established and save it in unitdata for access after the relation is removed.