Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Batch Laravel Package

yokai/batch

Yokai Batch is a Laravel package for running and managing batch jobs, with tools to define batches, track progress, and handle failures in queued workloads. It integrates with Laravel's queue and provides a simple API for orchestrating long-running or bulk tasks.

View on GitHub
Deep Wiki
Context7

Getting Started

yokai/batch is a framework-agnostic PHP implementation of Spring-Batch-style concepts: a Job is composed of Steps, a step is either a Tasklet (one unit of work) or an ItemStep (chunk-oriented read → process → write), and a JobLauncher executes jobs while a JobExecutionRepository records their state.

Minimal path:

  1. Install the core library: composer require yokai/batch.
  2. If you are on Symfony, add the bundle (yokai/batch-bundle); on Laravel there is no first-party integration, so register the services yourself in a service provider.
  3. Read src/Job, src/Step, src/Item, src/Launcher and the tests/ directory first — tests are the most reliable documentation for this package.
  4. Build one trivial job to validate the wiring:
use Yokai\Batch\Job\SimpleJob;
use Yokai\Batch\Step\SimpleStep;
use Yokai\Batch\Tasklet\CallbackTasklet;

$job = new SimpleJob('nightly-cleanup', [
    new SimpleStep('purge', new CallbackTasklet(function () {
        // one-off logic: delete stale rows, warm a cache, etc.
    })),
]);
  1. Register the job in a JobRegistry, construct a SimpleJobLauncher with a JobExecutionRepository (in-memory for a smoke test), and call ->launch('nightly-cleanup', new JobParameters()).

First real use case: a CSV/API importer. Use an ItemStep with a streaming ItemReader (yields rows), an optional ItemProcessor (normalise/validate), and an ItemWriter (persist per chunk). This gives you bounded memory and per-chunk flush semantics without writing your own loop.

Implementation Patterns

Chunk-oriented steps are the default pattern. Prefer ItemStep over a fat Tasklet whenever you are transforming a stream. The chunk size is the main tuning knob: it controls memory, transaction/flush frequency, and how much work is lost on a mid-step failure.

new ItemStep(
    name: 'import-customers',
    reader: new CsvReader($path),
    writer: new CustomerWriter($repository),
    processor: new CustomerProcessor(),
    batchSize: 100,
);

Tasklets for everything that isn't read/process/write. Cleanup, notifications, file moves, cache rebuilds, “mark stale rows” — a CallbackTasklet keeps the job definition readable and keeps orchestration in one place.

Compose multi-step jobs sequentially. Split a pipeline into download → validate → import → report steps. Each step gets its own StepExecution, so failures are localised and the execution record tells you exactly where the job stopped.

Pass everything through JobParameters. File paths, date windows, tenant IDs, dry-run flags — never read ambient globals from a reader/writer. This makes jobs reproducible and lets you launch the same definition from a controller, an Artisan command, or a queue worker.

Launch from your existing entry points. In Laravel, wrap the launcher in an Artisan command and dispatch it to a queue:

Artisan::command('batch:run {job} {--param=*}', function () {
    $this->launcher->launch($this->argument('job'), new JobParameters($this->option('param')));
});

Keep the command thin; the job should be runnable without the console.

Treat the execution repository as your observability layer. Query last execution status/start/end times to build a status endpoint or dashboard, and to decide whether a job is safe to re-run. For anything beyond a demo, back it with a persistent store (Doctrine-backed repository in the Symfony bundle, or your own implementation for Laravel) rather than the in-memory one.

Decorate rather than subclass. The interfaces (Job, Step, Tasklet, ItemReader/Processor/Writer, JobLauncher) are small, so wrapping a launcher to add logging, metrics, locking, or “skip if already running” is straightforward and keeps the core definitions clean.

Make writers idempotent. Jobs will be re-run after failures. Upserts keyed on a natural identifier (or a “delete window then insert” strategy) beat plain inserts.

Gotchas and Tips

  • This is a small, low-adoption package (12 stars, last release Dec 2023). Expect to read source and tests rather than docs. Pin the version in composer.json and audit PHP version constraints before committing.
  • Do not confuse it with Laravel’s Bus::batch. The naming overlaps, but this library owns job/step lifecycle, not queue fan-out. You still need a queue/worker to run it in the background.
  • The in-memory repository loses everything on process exit. Fine for tests, useless for restartability or “did last night’s import finish?”. Wire a persistent repository early — retrofitting it later means reworking your operational tooling.
  • Job parameter serialisation is lossy. Everything tends to become a string when persisted; normalise types in your reader/processor rather than trusting the parameter bag to preserve ints, dates, or enums.
  • Chunk size has two failure modes. Too large and you blow memory or hold locks too long; too small and per-chunk overhead dominates. Start around 100–500 and measure. A reader that eagerly loads the whole file defeats the point — stream with generators.
  • Step failure semantics are not transactional by default. A writer that partially flushed before an exception leaves partial data. Either wrap the writer in your own transaction per chunk or design for idempotent re-runs.
  • Exceptions are the control flow for failure. Throwing from a tasklet/reader/processor/writer marks the step failed; swallowing exceptions silently turns a broken job into a “successful” one. Log and rethrow unless you deliberately want skip semantics.
  • There is no Laravel service provider. You will write the container bindings for JobRegistry, SimpleJobLauncher, and the repository yourself. Keep that wiring in one provider so job definitions stay declarative.
  • Extension points beat forking. Custom ItemReader/ItemWriter implementations, a custom JobExecutionRepository, and launcher decorators cover almost every integration need without touching the library.
  • Add a concurrency guard. Nothing prevents two launches of the same job. A unique constraint on “running job name” in your execution store, or a cache lock around the launcher, is cheap insurance.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle