Skip to main content
Version: next

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.