Keeping it running
Run the agent as a resident process on one side and under a scheduler on the other.
The agent does one cycle per invocation. Something has to invoke it repeatedly, and the two sides are usually set up differently.
Local — resident watch mode
On the school's machine there is usually no reliable scheduler, so run the agent as a
resident process. It sleeps on the school's sync interval and stops cleanly on Ctrl+C:
cd C:\laragon\www\pac_local
.\sync-agent\sync-agent-windows-x64.exe --watchIt opens with the settings it resolved, then adds a line per cycle and counts down to the next one in place:
sync-agent PAC001 LOCAL
server http://localhost:3002
database pac_local at 127.0.0.1:3306
syncing captures UP, applies DOWN
interval 5 min
Ctrl+C to stop
15:30:04 DOWN applied 3, skipped 1 · UP pushed 12 1.1s
15:30:13 idle 864ms
next run in 4:51A failed cycle costs one tick — the agent reports the error and retries on the next one, so a database restart or a brief network outage recovers on its own. For unattended installs, register this under a service supervisor so it restarts on reboot.
Online — one-shot under the scheduler
The online database sits on a server that already has a scheduler, which gives you crash and reboot recovery for free. Run the agent one-shot on a timer instead:
$schedule->exec(base_path('sync-agent/sync-agent-windows-x64.exe'))
->everyMinute()
->withoutOverlapping()
->runInBackground();Tick faster than the sync interval
The scheduler frequency is a floor on the sync interval. If it fires every 5 minutes and the school's interval is 5 minutes, each cycle lands a couple of seconds short of its own slot and syncing happens every 10 minutes instead. Run it every minute and let the school interval do the throttling.
Overlapping runs
Overlap is safe: the agent takes a MySQL advisory lock before draining, so a slow run makes
the next one skip with another run is still in progress rather than draining the same rows
twice. The lock releases itself when the connection closes, including on a crash.
The lock is named after the database, not the school. Two agents on one MySQL host pointing at different databases never block each other, and two agents pointed at the same database will.
Remove any previous sync job
If the host application has its own sync command scheduled, remove it first. Two processes draining the same outbox will fight over rows.
Changing the interval later
A new sync interval takes effect without touching the host. A watch-mode agent checks in with the server every couple of seconds while it waits, and picks up the change in the wait already under way:
interval changed to 1 min
next run in 0:48The wait is measured from when it began. Lengthening the interval pushes the next run back. Shortening it past the time already waited starts the next cycle straight away. This holds after a failed cycle too: an agent stuck on an error retries on the dashboard's interval, and falls back to 5 minutes only while it cannot reach the server at all.
A one-shot agent never acts on the interval at all — the scheduler sets its cadence, and the dashboard value is a record of intent.
An agent started with --interval ignores the dashboard value entirely.