Sync Monitoring

Get started

Create a school, sync one table, and watch a change travel from the local database to the online one.

This tutorial takes you from an empty dashboard to one table syncing, and finishes with you editing a row in the school's local database and watching it appear in the online one.

You will configure a single table in a single direction. That is deliberately less than a real deployment needs, and it is the shortest path to seeing the whole system work.

What you need

  • Two MySQL databases you can connect to: the school's on-site database and the online one.
  • The same table present in both, with the same primary key. This tutorial uses students.
  • A MySQL user that can CREATE TRIGGER on the local database and write to the online one.
  • The agent executable for your platform, and the address of your monitoring server.

Create the school

In the dashboard, press Create School and fill in the dialog:

FieldValue
NameRiverside Academy
CodeRIV001
Sync interval5

Leave Status as Active and the generated Setup token as it is.

Copy the setup token now and keep it next to this page — you need it twice, and it is shown only in this dialog. The server stores a hash of it, so once you save, the full value cannot be recovered.

Press save. Riverside Academy appears in the list with Last seen empty, because no agent has contacted the server yet.

Add one table

Open the school, go to the Sync tables tab, and press Add sync table:

FieldValue
Table namestudents
Primary key columnid
Apply order100
DirectionUp
Create new rowson
Update existing rowson
Delete rowsoff

Up means the school's local database owns this table: changes made on-site travel to the online copy, and not the other way round.

Create the capture triggers

Configuring the table tells the server what to expect. It does not yet capture anything — that is done by database triggers.

Still on Sync tables, press Setup SQL. The Capture setup script dialog opens with two tabs, one per database, because each database gets its own script:

TabRun it onCaptures
Local databaseThe school's on-site databaseThe Up tables
Online databaseThe online databaseThe Down tables

A trigger has to live in the database where the edit happens. students is Up, so it is edited on the local database, and that is the only place its triggers are useful. Stay on the Local database tab — it opens there by default. Check that the line above the script reads Captures UP: students.

Get the script out of the dialog in whichever way suits the tool you run SQL with:

  • Copy puts the whole script on the clipboard. Paste it into SQLyog, HeidiSQL or any client that understands DELIMITER, and execute it there against the local database.
  • Download .sql saves it as a file named after the school code and the side — riv001-local-outbox.sql here. Pipe it into the MySQL command line client:
mysql -u root -p school_local < riv001-local-outbox.sql

Run it where the tab says

The script only works on the database its tab names. Running the local script on the online database puts the triggers on the wrong side, and edits made on-site are never captured.

This creates a sync_outbox table and three triggers on students, one each for insert, update and delete (sync_students_ai, _au, _ad). Confirm they exist:

SHOW TRIGGERS LIKE 'students';

The Online database tab is empty, and that is correct

You configured one Up table and no Down tables, so the online database has nothing to capture. Its tab says no active DOWN tables are configured, and Copy and Download .sql are disabled there. The online database gets no sync_outbox either, and does not need one: an agent with nothing to capture never reads it.

Add a Down table, and the online database needs its script

The first Down table gives the Online database tab a script. Run it on the online database before the online agent's next cycle. Until you do, every cycle there fails with:

! Table 'school_online.sync_outbox' doesn't exist

The same message on the local side means the Local database script was never run there.

Start the local agent

The agent lives inside the school's application, next to the code that already talks to the local database. On the school's machine, create a sync-agent/ folder in the application root and put the executable in it:

C:\laragon\www\riverside_local\
├── app\
├── public\
├── sync-agent\
│   └── sync-agent-windows-x64.exe
└── .env

Only public/ is web-served, so the binary cannot be reached over HTTP. If the application root is a git repository, add sync-agent/ to its .gitignore so the roughly 117 MB binary is never committed.

The agent reads .env from the directory you run it from, and does not search parent directories. You will run it from the application root, so it reads the application's own .env. The database settings are already there, and the agent accepts Laravel's spelling of them. Append the four monitoring settings to the end of that file:

.env
# ...the application's existing settings, which the agent reuses:
DB_HOST=127.0.0.1
DB_USERNAME=root
DB_PASSWORD=your-password
DB_DATABASE=school_local

# Sync agent: which server to report to, and which school this agent belongs to
MONITORING_URL=https://monitoring.example.com
SCHOOL_CODE=RIV001
SYNC_TOKEN=the-token-you-copied

# Which database this agent sits on: LOCAL (the school's on-site database) or ONLINE.
# LOCAL captures the Up tables and applies Down changes. The online agent uses ONLINE.
SYNC_SOURCE=LOCAL

No application on this machine?

The agent does not need one. Put the executable in any folder, create a .env beside it holding the settings above, and run it from that folder. Use DB_USER and DB_NAME or the Laravel names — the agent reads either.

SYNC_SOURCE is the one setting that tells the two agents apart. It has to match the database in the DB_* settings and the Setup SQL tab you ran on that database — LOCAL here, because this agent sits on the database where you ran the Local database script. It defaults to LOCAL, and any value other than ONLINE counts as LOCAL, so a typo on the online side silently turns that agent into a second local one.

Run it once, from the application root:

cd C:\laragon\www\riverside_local
.\sync-agent\sync-agent-windows-x64.exe

It prints one line and exits. Nothing has changed in the database yet, so the line reads idle — possibly alongside counted 1, if the cycle also reported row counts.

Go back to the school's Overview. Last seen now holds a timestamp: the agent reached the server and authenticated. Last sync is still empty, because no data has moved.

Start the online agent

Do the same on the host that runs the online application: a sync-agent/ folder in its application root, holding the executable for that host's platform. Its .env already points at the online database. The monitoring settings you append are the same as on the local side, except SYNC_SOURCE:

.env
# ...the online application's existing settings, which the agent reuses:
DB_HOST=127.0.0.1
DB_USERNAME=root
DB_PASSWORD=your-password
DB_DATABASE=school_online

# Sync agent: same server, school and token as the local agent
MONITORING_URL=https://monitoring.example.com
SCHOOL_CODE=RIV001
SYNC_TOKEN=the-token-you-copied

# ONLINE: this agent sits on the online database.
# It captures the Down tables and applies Up changes, the reverse of the local agent.
SYNC_SOURCE=ONLINE

Run it once from that application root — on a Linux host:

./sync-agent/sync-agent-linux-x64

It prints idle as well — the local side has captured nothing for it to apply.

This agent captures nothing itself, since there are no Down tables. Its job in this tutorial is to apply what the local side sends.

Change a row and follow it

On the school's local database, edit one row:

UPDATE students SET last_name = 'Fernandez' WHERE id = 1;

The trigger has already written that change to sync_outbox. Now run the local agent again, from the local application root:

.\sync-agent\sync-agent-windows-x64.exe

The line now reads UP pushed 1. The change is on the server, queued for the other side.

Run the online agent, from the online application root:

./sync-agent/sync-agent-linux-x64

It reads UP applied 1. Query the online database and the row has the new surname:

SELECT last_name FROM students WHERE id = 1;

Confirm it in the dashboard

Open the school's Overview. Last sync now holds a timestamp, and Table Monitoring lists students with a row count from each side.

The Sync history tab has runs in it, each marked Success. One is the push from the local agent; one is the apply from the online agent.

What you have now

One table syncing in one direction, with two agents you run by hand. A change made on-site reaches the online database the next time both agents run.

Three things stand between this and a working deployment:

  • The agents run once per invocation. Something has to invoke them repeatedly.
  • Only students syncs, and only upward. Every table needs configuring, per direction.
  • Only the local database captures. Re-run the setup SQL after every change to the table list.

Triggers only capture what happens after they exist

Rows that were already in students before you ran the setup SQL have never been captured, so the two sides can hold different data even though sync is working. Request a backfill for the table to send them.

On this page