Playing on Hard
Connascence of Execution

Per connascence.io:

Connascence of execution is when the order of execution of multiple components is important.

In connascence of value one of the dynamic solution I proposed was:

a Kubernetes service that subscribes to etcd and that on received changes redeploys a set of all the other Kubernetes services that depend on the updated values

But such a service, as specified in the post, doesn’t solve the dependancy of order of redeploys. Indeed, such order of redeploys is an example of connascence of execution, where, rather than execution, the order of updating of the components matters for correctness.

To solve it, our hypothetical component, let’s call it etald, would have to be configured (yay) to upgrade the services in the correct order. But would such an order be stable between deployments? Only if the dependencies never changed (yeah, right) and any backward compatibility shims would always be written with the same dependency direction.

For example, imagine services A and B, with A dependending on B, and both having to change due to a new feature. You don’t want any formal downtime (taking the services down) let alone informal (letting the services crash during the window of deployment). You now have the following choices:

  1. Deploy the new versions of the services alongside the old version, making sure that A’ depends on B’, not B. But if we had to do that automatically the convention (aka connascence of algorithm) would have to be more elaborate than before: etald would have to know the name of the environment variable in A that it uses to invoke B. etald would also have to be able to create whole new services rather than just upgrade the ones already there.
  2. Define the order of the upgrades in the configuration of etald and making sure that, whatever the order may be, the first service being upgraded is always backward compatible with the previous verison of the second service.

Neither of these choices is great - it’s more work any way you look at it. Keeping A and B in the same release lifecycle should make the problem easy but it actually does not simply because the underlying substrate does not treat version as 1st class citizen. An ideal deployment would be atomic and easy. Both solutions can be made to be atomic but neither is easy (they are not hard, just fragile over time as the standard tooling cannot describe “always code A in backward comparible manner” or “A’ should invoke B’”)

However, “A’ should invoke B’” can be easily expressed in AWS lambda: if A and B were lambdas, A’ could always just invoke B’, without concerns of invoking some other B. Then you can leisurely deploy A’ and B’ and if both succeed transition the requests to A’. Rolling back is also easy: simply switch the requests back to A (which will always execute B rather thab B’). If A’ and B’ communicate through queues then make A’ write to queue Q’ and have B’ listen to Q’. Then A and B will naturally wrap up the work they already have in the queue Q and in the meantime A’ will have started pushing items to Q'.

I now realize that I have written only about the connascence of execution from the point of view of deployments. So here’s one for the road - deadlock:

In concurrent computing, a deadlock is a state in which each member of a group waits for another member, including itself, to take action, such as sending a message or more commonly releasing a lock. Deadlocks are a common problem in multiprocessing systems, parallel computing, and distributed systems, where software and hardware locks are used to arbitrate shared resources and implement process synchronization.

The deadlocks thus occur when there is a connascence of execution and certain locks have to, always, be acquired in the same order to avoid processes waiting for other processes that are waiting for themselves in the first place. Thus to solve the deadlocks, you have to replace the connascence of execution with the connascence of algorithm:

Connascence of algorithm is when multiple components must agree on a particular algorithm.

The algorithm in question being “always acquire locks in the same order” of course.


Last modified on 2021-05-06