Sync Monitoring

How it works

Direction, the journey of a single change, and why a school runs on one clock.

The Overview names the pieces. This page follows a single change from the moment it is saved to the moment the other database holds the same value, and explains the rules that shape that journey.

Direction

Each table is configured with a direction, which decides who is allowed to originate a change to it.

  • UP — the school edits it on-site; the online copy follows. Anything recorded during day-to-day work at the school.
  • DOWN — it is edited through the online system; the school's copy follows. Anything administered centrally.

A side only captures the tables it owns, which is why the setup SQL differs per database. The same table can be listed in both directions when both sides legitimately edit it.

Applied writes are not re-captured

Before applying anything, the agent sets a session variable that every trigger checks. The writes it makes are therefore invisible to the outbox, so a change never echoes back to the side it came from.

A change, end to end

The outbox stores only a table name and a row id, never a copy of the row. The agent reads the row's current state at push time, so ten edits between two cycles ship once, as the final value. That is also why a delete and a re-insert of the same key collapse correctly.

A captured change is dropped rather than pushed when its table is no longer configured, or when the table does not permit that operation — a table set to ignore deletes, for example. Dropping it at the agent keeps one disallowed change from getting the whole batch rejected and wedging the outbox.

Timing

Each school has one sync interval, shared by all of its tables. A single clock means everything captured in a window ships in the same batch, which is what keeps apply order meaningful — a per-table clock could send a child in a cycle where its parent was not due.

Who honours that interval depends on how the agent runs. By default it performs one cycle and exits, so an external scheduler sets the cadence and the dashboard value is a record of intent rather than the thing driving the clock. Under --watch the agent re-reads the interval from the server every cycle, so changing it in the dashboard takes effect without restarting anything — unless the agent was started with its own --interval, which wins.

Two runs against the same database cannot overlap, so an aggressive schedule is harmless — the agent explains how that is enforced.

When a change cannot be applied

Two things stop a change landing, and they behave differently.

An error — a missing parent row, a column that exists on one side but not the other — stops the cycle at that change. The agent refuses to acknowledge past it, so the queue holds its position and retries next cycle. Nothing after it is applied. The school's Queue tab shows the change and its error, and lets you retry it or skip it.

A conflict is different: the row is refused on purpose, because the receiving side already holds a different row under that key. The cursor still advances, so the rest of the queue keeps moving, and the disputed key is held until someone decides which version wins.

On this page