Skip to main content
Version: v1

Scheduling syncs

The package ships no hardcoded schedule — you own the cadence. The proven pattern is frequent deltas plus one nightly full snapshot. Deltas keep prices and stock fresh; the nightly full re-establishes the baseline and reconciles hard deletes.

Prerequisite: the system cron tick

Laravel's scheduler only runs when something invokes it once a minute. Add this single cron entry on the server (once):

crontab -e
* * * * * cd /path/to/app && php artisan schedule:run >> /dev/null 2>&1
The scheduler needs a once-a-minute tick

Without the * * * * * php artisan schedule:run entry above, no scheduled command ever fires — the Schedule::command(...) definitions below are inert until something invokes the scheduler each minute. On managed/PaaS hosts use their scheduler feature to run php artisan schedule:run every minute.

Let the package schedule it for you

You don't have to touch routes/console.php at all. Flip one env var and the package registers both tasks (frequent deltas + a nightly full) itself:

.env
VOICEBOT_SCHEDULE_ENABLED=true
# optional — defaults shown
VOICEBOT_SCHEDULE_DELTA_CRON="*/15 * * * *"
VOICEBOT_SCHEDULE_FULL_CRON="0 3 * * *"

php artisan voicebot:install walks you through the rest (publish config, migrate, pair) and points you here. You still need the once-a-minute cron tick above — the flag only registers the tasks; the system cron is what fires them. Confirm with php artisan schedule:list.

Prefer to own the cadence in code (custom intervals, conditions, queues)? Leave the flag off and define the tasks yourself, below.

Define the schedule

Where you register scheduled tasks depends on your Laravel version. Both register the same two commands — frequent deltas and a nightly full.

Laravel 11+ defines scheduled tasks in routes/console.php using the Schedule facade:

routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('voicebot:sync')
->everyFifteenMinutes()
->withoutOverlapping();

Schedule::command('voicebot:sync --full')
->dailyAt('03:00')
->withoutOverlapping();
Always use withoutOverlapping()

A long sync that runs past its next tick must not start a second copy. withoutOverlapping() skips the overlapping run; the watermark means the next run picks up exactly where the skipped one would have. For large catalogs, prefer the --queue flag so the scheduled command returns fast and a worker does the push (see Operations).

Delta vs --full

voicebot:sync (delta)voicebot:sync --full (snapshot)
What it sendsOnly rows changed since the per-kind watermarkA complete snapshot of every enabled kind
Transport/events batchesgzip-NDJSON file upload
FrequencyOften (minutes)Once nightly (and once at first setup)
DeletesSoft deletes onlyReconciles hard deletes via server tombstones
CostTiny — proportional to churnProportional to catalog size

Why a nightly full

Deltas are driven by your updated_at column and the SoftDeletes trait. Two things they cannot catch on their own:

  • Hard deletes — a row deleted outright leaves no updated_at to observe. The full snapshot's server-side tombstone pass removes anything no longer present.
  • Out-of-band edits — a bulk SQL update or an import that bypasses Eloquent timestamps won't move updated_at, so deltas miss it. The nightly full re-syncs everything regardless.

The nightly --full is your safety net. After it completes, the watermark for every kind is advanced to the snapshot start, so the next delta only carries post-snapshot changes.

Tuning the cadence

Match delta frequency to how fast your catalog changes:

  • High-churn store (prices/stock move constantly) → ->everyFiveMinutes().
  • Typical store → ->everyFifteenMinutes() (the example above).
  • Mostly-static catalog → ->hourly(), relying more on the nightly full.

Schedule the nightly --full for a low-traffic hour (the 03:00 above) so the larger upload doesn't compete with peak load. Stagger it off exact-hour boundaries if you run many apps against the same backend.

Verifying the schedule

List what Laravel will run and when:

Terminal
php artisan schedule:list

Run a one-off delta by hand to confirm the wiring before trusting cron:

Terminal
php artisan voicebot:sync --dry-run # computes + prints what WOULD be sent; pushes nothing

Exit codes and what cron should alert on are covered in Operations → Exit codes.