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):
* * * * * cd /path/to/app && php artisan schedule:run >> /dev/null 2>&1
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:
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 / 12 / 13
- Laravel 10 (and earlier)
Laravel 11+ defines scheduled tasks in routes/console.php using the Schedule facade:
use Illuminate\Support\Facades\Schedule;
Schedule::command('voicebot:sync')
->everyFifteenMinutes()
->withoutOverlapping();
Schedule::command('voicebot:sync --full')
->dailyAt('03:00')
->withoutOverlapping();
On Laravel 10 the schedule lives in the console kernel's schedule() method:
protected function schedule(\Illuminate\Console\Scheduling\Schedule $schedule): void
{
$schedule->command('voicebot:sync')
->everyFifteenMinutes()
->withoutOverlapping();
$schedule->command('voicebot:sync --full')
->dailyAt('03:00')
->withoutOverlapping();
}
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 sends | Only rows changed since the per-kind watermark | A complete snapshot of every enabled kind |
| Transport | /events batches | gzip-NDJSON file upload |
| Frequency | Often (minutes) | Once nightly (and once at first setup) |
| Deletes | Soft deletes only | Reconciles hard deletes via server tombstones |
| Cost | Tiny — proportional to churn | Proportional 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_atto 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:
php artisan schedule:list
Run a one-off delta by hand to confirm the wiring before trusting cron:
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.