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

Laravel Chores Laravel Package

amrlotfy/laravel-chores

amrlotfy/laravel-chores offers a lightweight way to define and manage recurring household chores in Laravel apps, with scheduling, assignments, and completion tracking. Eloquent-friendly models and simple configuration help you add chore rotations without building the plumbing yourself.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and inspect, in this order:

composer require amrlotfy/laravel-chores
php artisan vendor:publish --tag=chores-config   # confirm the actual tag in the README

This is a 35-star package with a narrow surface area — read src/ before you trust it in production. The whole thing is probably under a dozen files, so spend ten minutes on:

  1. src/*ServiceProvider.php — what's registered, what commands exist, whether a migration/table is auto-loaded.
  2. config/chores.php — batch size, checkpoint store (cache vs. database), lock/lease settings, TTL.
  3. src/Console/ — the run/resume/list commands and their exact signatures.
  4. The chore base class or contract your job will implement — this determines whether your logic receives a chunk of models, an ID range, or nothing but a cursor.

Checkpoint storage is your first decision. If checkpoints live in the cache and your cache is Redis with an eviction policy (or CACHE_STORE=array in a queue worker that restarts), you can silently lose progress. For anything important, point the checkpoint store at the database and run the package's migration.

First use case worth doing: backfilling a nullable column on a large table.

// Keep the body idempotent and side-effect-scoped to the chunk.
class BackfillOrderRegion extends Chore
{
    protected int $chunkSize = 1000;
    protected string $keyColumn = 'id';   // must be monotonic — see Gotchas

    public function handle(Collection $orders): void
    {
        foreach ($orders as $order) {
            if ($order->region !== null) {
                continue; // already done — makes replays free
            }
            $order->forceFill(['region' => RegionResolver::for($order)])->saveQuietly();
        }
    }
}

Run it in staging first, hit Ctrl+C halfway, run it again, and confirm it resumes rather than restarting. That single test tells you whether the package's core promise holds in your environment — and it's the test most people skip.

Implementation Patterns

Treat a chore as a restartable job, not a script. The package's value is the checkpoint; everything else is Laravel you already know. Structure work so that "batch N succeeded" is a durable, meaningful fact.

Chunk-by-primary-key is the default pattern for backfills and cleanups. Monotonic ID iteration is what makes resume safe. For cleanups:

public function handle(Collection $rows): void
{
    // Delete only what still matches the predicate at execution time.
    Order::whereIn('id', $rows->pluck('id'))
        ->whereNull('customer_id')
        ->where('created_at', '<', now()->subYear())
        ->delete();
}

Run it from the deploy pipeline, not from a person's laptop. A common integration is an artisan call in your release script after migrate, with the chore no-opping when its checkpoint says "done." That gives you backfills that survive the Ctrl+C on a dropped SSH session and the container restart mid-deploy — which is the actual problem this package solves.

Separate "run" from "supervise." Foreground for small one-offs; a queued job or a supervisor-managed process for long backfills. Either way, put an exclusive lock around the run (Cache::lock) so a retried deploy step and a manual invocation can't race the same checkpoint.

Prefer small batch sizes with quiet model events (saveQuietly, withoutEvents) during data movement. Observers firing on 500k rows is how backfills turn into incident reports.

Use it for irreversible-ish migrations of shape: splitting a column, normalizing enum values, re-deriving a denormalized counter. The resume property matters most when re-running from zero costs hours.

Log per batch, not per row. Chore ID, cursor/offset, rows affected, duration. That log line is what you'll grep at 2am to answer "how far did it get."

Gotchas and Tips

Monotonic keys only. If you chunk on updated_at or a UUIDv4, resume will skip or duplicate rows — and the package cannot know that. id (or a sequence column) is the only safe cursor. If your table is UUID-keyed, chunk on an indexed created_at, id tuple or add an integer cursor column.

Resume is not repair. If a batch crashed mid-transaction, the checkpoint may have advanced past work that didn't commit. Wrap each batch in a transaction if partial application is unacceptable, and make handle() idempotent regardless — it's the only real safety net.

SIGINT is handled; SIGKILL isn't. Ctrl+C and (usually) SIGTERM can be caught to finish the current batch and persist the checkpoint. docker kill, OOM, and --no-ack worker deaths cannot. Verify the graceful path explicitly — run it, send SIGTERM, and check the checkpoint moved.

Flushed cache = silent full restart. Cache-backed checkpoints are the number-one footgun. Use the DB store, or pin the cache key with no TTL and an eviction-exempt policy.

Two runners will double-process. The package checkpoints progress; it likely doesn't guarantee mutual exclusion. Add your own lock.

Idempotency is your responsibility, not the package's. Re-running a partially-applied batch is the expected failure mode. Guard with whereNull(...) or upsert, never with blind increment().

Tune batch size against two limits: memory (hydrating models) and lock/transaction duration. Start at 500–1000 for model work, 5k–10k for DB::table() updates. Halve it if you see replica lag or lock timeouts.

Test at chunkSize = 3. Small batches surface checkpoint off-by-ones, boundary rows, and re-entrancy bugs in seconds that take an hour to find at 1000.

Extension points worth knowing: the checkpoint store (swap to Redis/DB/custom), the console command options (dry-run, --from, --chunk), and the base class's lifecycle hooks if it exposes them. If it doesn't expose a dry-run, add one to your chore's handle() — you'll want it.

Budget for maintenance risk. 35 stars and a single maintainer means no security patch guarantee and possible abandonment. It's MIT and small: read every line, pin the exact version, and be prepared to fork. If the only feature you need is "chunk + store an offset," a 40-line custom command with a Cache::forever counter may be a better dependency.

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.
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
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource