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

Background Task Bundle Laravel Package

text-media/background-task-bundle

A Symfony bundle for offloading work to background tasks. Persist and manage jobs, run them asynchronously with workers, and keep long-running processes out of web requests. Includes task handling and queue-style processing for PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

This bundle is a Symfony integration for the text-media/background-task-bundle package. First, install it via Composer and register the bundle in config/bundles.php:

TextMedia\BackgroundTaskBundle\TextMediaBackgroundTaskBundle::class => ['all' => true],

Run the bundle's Doctrine migrations (or schema update) — the package ships with its own entity for persisting task records, so you need the table in place before anything works:

bin/console doctrine:migrations:diff
bin/console doctrine:migrations:migrate

Check bin/console list for a background-task:* namespace — that's your entry point. Typically you'll find a run or process command that acts as the worker. Add it to your crontab or a supervisor process:

bin/console background-task:run

First use case: the canonical pattern is "kick off something slow from a web request without blocking the response." Create a task record in your controller, return immediately, and let the cron-driven worker pick it up:

$task = new BackgroundTask();
$task->setCommand('app:generate-report');
$task->setArguments(['--user' => $user->getId()]);
$taskManager->persist($task);

Implementation Patterns

Task-as-command pattern. The cleanest integration is to keep the actual work inside ordinary Symfony commands, and let the bundle only handle persistence, scheduling, and pickup. Your controller just enqueues a reference. This keeps the work testable independently and makes it trivial to run the same logic synchronously in a test.

Worker loop / cron. The bundle assumes a pull model: a recurring process scans the table for pending tasks and executes them. Two deployment styles work:

  • Cron tick — call the worker command every minute from crontab. Simple, but adds up to ~60s of latency.
  • Daemon loop — run the worker with a long-lived flag (check the command's --help for a --daemon/--loop option; if absent, wrap it in a while true; do ... sleep 5; done). Lower latency, but you need supervisor to restart it.

Idempotency by task ID. Always make the underlying command idempotent and keyed on the task ID. If the worker crashes mid-run, the task will be retried on the next sweep. Log task->getId() at the top of your command so you can correlate.

Chaining. For multi-step workflows, have the command create the next BackgroundTask at the end rather than looping inside one task. Each step gets its own retry budget and its own log line, and you avoid a single stuck task blocking the whole pipeline.

Status fields as your API. The entity almost certainly exposes status (pending, running, done, failed) and possibly result/error columns. Use these for a lightweight UI — a "Jobs" admin page reading pending/failed counts is often the fastest way for support to diagnose "why isn't my export ready."

$repo->count(['status' => BackgroundTask::STATUS_PENDING]);

Integration with Symfony Messenger. If you later adopt Messenger, you can either replace this bundle's worker with a Messenger transport, or keep both: enqueue the BackgroundTask synchronously and have a Messenger handler invoke the same underlying command. Don't run both workers against the same table — you'll double-execute.

Gotchas and Tips

Two processes, one table. Cron plus a supervisor daemon is a common footgun — both workers will pick up the same pending row unless the bundle uses row locking (e.g. SELECT ... FOR UPDATE or a status-claim update). Check the repository's claim logic before deploying both; if it's a naive SELECT then UPDATE, run exactly one worker process.

Retry storms. A broken command will fail, get retried next sweep, fail again, forever. Set a maxAttempts on the task if the entity supports it, and add alerting on failed counts. A failed task with no alert is silent for days.

Logging. The worker's stdout is almost never captured where you expect. Ensure Monolog is configured to write command-channel logs, and include the task ID in your command's logger->info() calls. Without that, debugging a stuck task means grepping timestamps.

Long-running commands vs. cron overlap. If a task takes longer than your cron interval, you'll stack workers. Use flock on a lockfile in the cron entry, or prefer the daemon + supervisor model where the process count is explicit.

Memory. Daemon-mode workers leak — Doctrine's entity manager holds references. If the loop flag exists, check whether it calls $em->clear() between iterations. If not, either restart the worker every N tasks (supervisor handles this) or patch the loop.

Extension points. The bundle likely dispatches Symfony events around task lifecycle (pre-run, post-run, failure). Check TextMedia\BackgroundTaskBundle\Event\ before writing your own hooks — a listener that emails on failure, or one that records duration metrics, is usually cleaner than baking that into the command. Also look at whether the task executor is a service you can decorate (decoration: .inner) to swap Process execution for a queued transport later.

Config quirks. Bundle configuration is typically namespaced under text_media_background_task: in config/packages/. Common knobs: the worker's polling interval, the Doctrine entity manager to use (multi-EM apps need explicit selection), and the PHP binary path for spawned subprocesses. The binary path one bites you on Docker — php in-container is rarely where the bundle's default expects it.

Version pinning. With zero dependents and no stars, this is a low-bus-factor package. Pin the exact version in composer.json and vendor-review upgrades — a Symfony minor bump could break it silently. If it's critical-path, keep a fork ready.

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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin