›
›
›
  1. docs
  2. ›
  3. byrcsc/laravel-data-sync
1.x
Browse documentationOpenClose

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • File identity and runs
  • Sync definitions
  • Sources and connections
  • File formats and readers
  • Field mapping
  • Matching and writing
  • Validation and hooks

Running syncs

  • Running a sync
  • Queues and workers
  • Scheduling

Transfers

  • File transfers

Operations

  • Run history and status
  • Events and listeners
  • Failures and retries
  • Sensitive data
  • Health checks
  • Retention and pruning

Reference

  • Configuration
  • Console commands
  • Testing
  • Troubleshooting

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • File identity and runs
  • Sync definitions
  • Sources and connections
  • File formats and readers
  • Field mapping
  • Matching and writing
  • Validation and hooks

Running syncs

  • Running a sync
  • Queues and workers
  • Scheduling

Transfers

  • File transfers

Operations

  • Run history and status
  • Events and listeners
  • Failures and retries
  • Sensitive data
  • Health checks
  • Retention and pruning

Reference

  • Configuration
  • Console commands
  • Testing
  • Troubleshooting

byrcsc/laravel-data-sync · 1.x

Events and listeners.

React to sync start, completion, and failure through Laravel events.

Three events carry the SyncRun model:

use ByRcsc\LaravelDataSync\Events\SyncCompleted;
use ByRcsc\LaravelDataSync\Events\SyncFailed;
use ByRcsc\LaravelDataSync\Events\SyncStarted;
EventDispatched when
SyncStartedA run moves to running, for queued runs, when the worker picks it up
SyncCompletedA run finishes as completed or completed_with_errors
SyncFailedA run finishes as failed or cancelled

All three expose the run:

$event->run->ulid;
$event->run->definition;
$event->run->status;
$event->run->dry_run;
$event->run->write_path;
$event->run->rows_created;
$event->run->rows_failed;
$event->run->error_summary;
$event->run->archive_path;
$event->run->file;          // the ledger row
$event->run->failures;      // SyncRowFailure records

The run passed to SyncCompleted and SyncFailed is reloaded after the final counters are written, so the numbers on it are the finished ones.

Package events are never queued

None of these events implement ShouldQueue. They are dispatched synchronously, inside the job or command doing the work, so a listener that calls a slow API blocks the sync, and on the queued path, blocks the batch's completion callback.

Queue the listener, not the event:

namespace App\Listeners;

use ByRcsc\LaravelDataSync\Events\SyncCompleted;
use Illuminate\Contracts\Queue\ShouldQueue;

final class NotifyMerchandising implements ShouldQueue
{
    public string $queue = 'notifications';

    public function handle(SyncCompleted $event): void
    {
        if ($event->run->dry_run || $event->run->rows_failed === 0) {
            return;
        }

        // notify, open a ticket, post to Slack ...
    }
}

Register it as you would any listener. The events serialize their models, so a queued listener receives the run by key and reloads it, it sees the persisted record, not a stale in-memory snapshot.

Dry runs dispatch events too

A --dry-run records a run and dispatches SyncStarted and SyncCompleted like any other. That is useful for testing a listener, and a trap for one that notifies people. Guard with $event->run->dry_run.

What runs where

Understanding where a listener executes explains which failures it can cause:

PathEvents dispatched from
sync:run --nowThe command process
Queued, batchedSyncStarted from the file job; SyncCompleted / SyncFailed from the batch callback
Queued, atomic()The file job, inside the file's transaction
sync:retryThe dispatched job
sync:retry --failed-rowsThe command process

For an atomic() definition the completion event fires inside the file's transaction, so a synchronous listener that writes to the database is part of that transaction and rolls back with it. A queued listener is not, and may run before the transaction commits, dispatch it with afterCommit if it reads what the run wrote.

Follow-up work belongs here

The bulk write path dispatches no model events, which is exactly why it is fast. When a fast definition still needs per-import follow-up, reindexing a search collection, warming a cache, recalculating aggregates, put it in a queued SyncCompleted listener keyed on the definition:

public function handle(SyncCompleted $event): void
{
    if ($event->run->definition !== 'products' || $event->run->dry_run) {
        return;
    }

    ReindexProducts::dispatch();
}

That keeps the bulk path intact rather than paying per-row Eloquent costs for work that only needs to happen once per file.

What to read next

  • Matching and writing for why model events are absent on the bulk path.
  • Run history and status for the same data after the fact.
  • Failures and retries for what a SyncFailed listener should probably do.
PreviousRun history and statusNextFailures and retries
View source

On this page

  1. Package events are never queued
  2. Dry runs dispatch events too
  3. What runs where
  4. Follow-up work belongs here
  5. What to read next