Skip to content

Backfill API

Everything available on a class extending Kstmostofa\Backfill\Backfill.

Required

collection(): Builder

The rows to process. Make it self-excluding.

Any orderBy you add is stripped — keyset pagination is only correct when the sort matches the cursor column.

process($record): void

Apply the change to one row. Called when $hydrateModels is true (the default).

Runs inside its own savepoint, so throwing rolls back this row alone and records the failure.

Properties

PropertyDefaultDescription
$batchSizeconfigRows per batch
$sleepMsconfigMilliseconds between batches
$useTransactionstrueWrap each batch in a transaction. Leave it on
$hydrateModelstrueSet false for the query-builder fast path
$withoutModelEventsfalseSuppress observers for the run
$operatorRunnablefalseOffer this in the operator panel
$ledgerfalseRecord processed rows for external side effects
$externalSideEffectsfalseDeclares that process() reaches outside the database

$batchSize and $sleepMs fall back to backfill.batch_size and backfill.sleep_ms when not set on the class.

Optional methods

processBatch(Collection $rows): void

Whole-batch fast path, used when $hydrateModels = false. Rows arrive as stdClass.

guard(): bool

Return false to refuse to start. Checked before the lock is taken, so a refused run leaves nothing behind.

keyName(): string

Column to paginate over. Defaults to the model's primary key. Must be unique, sortable and indexed.

description(): string

Human-readable name, shown in backfill:list and the operator panel.

name(): string

The command-line name. Derived from the class name — BackfillUserSlugs becomes user-slugs — and rarely worth overriding.

An anonymous subclass answers to its parent's name, so a one-off tweak of a real backfill resumes and locks against the same run.

Hooks

php
public function beforeRun(BackfillRun $run): void {}
public function afterRun(BackfillRun $run): void {}
public function beforeBatch(Collection $rows, BackfillRun $run): void {}
public function afterBatch(Collection $rows, BackfillRun $run): void {}
public function onRowFailed($record, Throwable $e): void {}

beforeBatch and afterBatch run inside the batch transaction

Throwing from either rolls back the whole batch, cursor included.

Parameters

php
public function parameters(): array;          // declare
public function parameter(string $key, mixed $default = null): mixed;   // read
public function parameterValues(): array;
public function withParameters(array $values): static;

See the parameter reference.

Tenancy

php
public function tenants(): ?iterable;         // null = single-tenant
public function useTenant(string|int $tenant): void;

See multi-tenancy.

Run options

Passed as RunOptions to BackfillRunner::run(), or as an array to the test helper.

OptionTypeDescription
batchSize?intOverride rows per batch
sleepMs?intOverride the pause between batches
freshboolIgnore a resumable run
withoutEstimateboolSkip the COUNT
maxBatches?intStop cleanly after N batches
startedBy?stringAudit string recorded on the run
forceboolSkip production guards
parametersarrayValidated parameter values
tenant?stringWhich tenant's cursor this run belongs to
onBatch?Closurefn (BackfillRun $run, int $count)
onThrottle?Closurefn (ThrottleDecision $decision)

Running programmatically

php
use Kstmostofa\Backfill\Runner\BackfillRunner;
use Kstmostofa\Backfill\Runner\RunOptions;

$run = app(BackfillRunner::class)->run(new BackfillUserSlugs, new RunOptions(
    batchSize: 500,
    maxBatches: 10,
    startedBy: 'scheduler',
));

$runs = app(BackfillRunner::class)->runAll(new BackfillTenantInvoices);

resumableRun(Backfill $backfill, ?string $tenant = null) returns the run that would be continued, or null. It marks a stale run interrupted as a side effect.

Run statuses

StatusMeaningResumable
PendingCreated, not yet startedYes
RunningIn progress
PausedStopped cleanlyYes
InterruptedHard-killed; heartbeat went coldYes
FailedStopped with an errorYes
CompletedFinishedNo
CancelledStopped for goodNo

Released under the MIT Licence.