Skip to main content
A reconcile hook is a function that takes an effect key, asks the remote what happened, and answers "committed", "not_executed" or "unknown". It is the only thing besides a human permitted to move a record out of AMBIGUOUS, and it moves the record only in the direction its answer points: "unknown" leaves it where it was. Prerequisites: pip install ctrlrun, an empty directory. The remote is a stand-in with a lookup the hook can call.
1

Write the hook beside the executor

The hook receives the effect key and nothing else. Parse what you need out of it; the key was built from the arguments, so it carries the identifiers the remote indexes by.
runnable
runnable
2

Choose when it runs

With reconcile_eagerly=True the hook runs as soon as the call produces an AMBIGUOUS outcome. Without it, the hook runs when a later attempt is blocked by the ambiguous record, which is the cheaper default when reconciliation costs a network call and most ambiguous effects are never retried.
3

Read the evidence

runnable
The reconciliation is two events, RECONCILIATION_STARTED and RECONCILIATION_RESOLVED, with the hook’s answer. A hook that raises is recorded and the record stays AMBIGUOUS; it is never read as an answer.

The three answers

Answer "not_executed" only when the remote told you it has no record of the effect, and the remote is authoritative for that. A hook that answers it from a cache, or from a lookup that can lag, has the same failure as an executor raising NotExecuted too early: it licenses a second execution.

If it didn’t work

  • The record stayed AMBIGUOUS after an eager reconcile: the hook returned "unknown" or raised. Both are recorded in the events.
  • InvalidArgument: reconcile must be callable: reconcile= was given something other than a function of one argument.

Next