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 Job Status Laravel Package

imtigger/laravel-job-status

Track the status of queued Laravel jobs. Add the JobStatus trait to a job, then query its state (queued, processing, completed, failed), progress, messages, and errors through a simple API. Statuses persist in cache or database, so you can show job progress in your UI and debug failures easily.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package and publish its assets:

composer require <vendor>/<package>
php artisan vendor:publish --provider="<Vendor>\<Package>\<Package>ServiceProvider"
php artisan migrate

The publish step typically drops a config file (queue connection/table names, retention, enabled statuses) and a migration for the job status table. Read the config file first — it is the fastest map of what the package considers a "status transition" and which queue events it listens to.

Then look at, in this order:

  1. JobStatusUpdater — the class responsible for translating Laravel queue events (or explicit calls) into status rows. As of 1.2.0 this is now an extension point, so treat it as the package's primary seam.
  2. The service provider — shows whether the updater is bound as a singleton, whether it registers queue event listeners, and what it binds into the container.
  3. Any trait or base job class shipped with the package — determines how much boilerplate your jobs need.

First use case: put a long-running or business-critical job (invoice generation, report export, webhook delivery) on the tracked path, dispatch it, and watch the row move from queued → processing → completed. Confirm the row updates on a successful run and on a failed() run before you roll it out further. Two jobs are enough to validate; don't instrument the whole codebase up front.

Implementation Patterns

Trait/base-class on jobs. The lowest-friction pattern is applying the package trait (or extending its base job) on jobs you care about. Keep this opt-in per job rather than global — high-volume, fire-and-forget jobs (cache warmers, analytics pings) create table churn without giving anyone value.

Customizing JobStatusUpdater (new in 1.2.0). This is the headline feature for day-to-day work. Extend the class and override the mapping methods (event → status, payload → metadata) when you need to:

  • attach tenant/user/correlation IDs to the status row for support triage;
  • normalize status vocabulary to match an existing internal enum;
  • add redaction before payloads are persisted (never store full payloads containing PII or tokens);
  • emit your own domain event (e.g. ReportExportFailed) so notification logic lives in your app, not in the package.

Bind the subclass in a service provider:

$this->app->bind(
    \Vendor\Package\JobStatusUpdater::class,
    \App\Queue\CustomJobStatusUpdater::class
);

If the package binds it as a singleton, override with $this->app->singleton(...) instead — binding a bind() over an existing singleton() silently does nothing. Check the provider before writing the binding.

Retry-aware handling. 1.2.0 marks a job as failed when it exhausts its retry count. Align your jobs' $tries, backoff, and retryUntil with what the package expects — the updater reads the attempt count from the queue event, so a job that self-limits retries in handle() rather than via $tries will report differently than you'd guess. If your jobs do manual retry logic ($this->release()), decide explicitly whether intermediate attempts should show as retrying or stay processing in your UI.

Deploy-safety with deleted classes. Jobs whose class no longer exists now fail safe instead of throwing during status update. This matters most right after a deploy that removes or renames a job class while old payloads are still in the queue. Pair it with a periodic query for statuses stuck in queued/processing past a threshold — the package will not resolve them for you, but it won't crash the worker either.

Querying status. Build one small read model around the table — a scoped query or repository — rather than spreading where('status', ...) across controllers. When the package's schema changes, that's the single file to fix.

Testing. Use Queue::fake() to assert dispatch, but use the real queue (sync or database driver) in at least one feature test to verify the status row actually transitions. A faked queue never fires the events the updater listens to, so status assertions silently pass on empty tables.

Gotchas and Tips

  • The failed_jobs table is not replaced. This package tracks status; Laravel's own failed-job store and queue:failed tooling still work independently. Don't assume one implies the other, and don't build retry-from-dashboard logic on the status table alone.
  • Max-retry failure is a status write, not a re-throw. If you rely on exception bubbling to trigger your own alerting, verify it still happens. Put alerting in the job's failed() method or in a listener on Laravel's JobFailed event, not in the status row.
  • Container binding order. Bind your JobStatusUpdater subclass in register(), not boot(). If the package resolves the updater while registering queue listeners, a boot()-time binding arrives too late and you'll get the base class with no error.
  • Silent no-ops on misconfiguration. A wrong connection name or a disabled config flag usually means no rows and no exception. If nothing appears in the table, check the config and confirm queue:work is firing events (Horizon and queue:work both work; a custom worker loop might not).
  • Worker kills leave stale processing rows. There is no fail-safe for a SIGKILL'd worker. Add a scheduled command that reconciles rows older than your longest job runtime.
  • Payload persistence is the main privacy risk. Redact in the updater subclass before persisting, and set a retention window in config. Add a pruning schedule if the package doesn't ship one.
  • After upgrading, re-run migrations and clear config cache.
    php artisan migrate
    php artisan config:clear && php artisan queue:restart
    
    queue:restart matters here: workers running the old code will still execute the pre-1.2.0 updater until they cycle.
  • Extension point discipline. Overriding the updater is supported; overriding its internals (protected properties, method call order) is not. Keep the subclass thin — map, redact, emit — so future releases don't break you.
  • Watch the queue events you subscribe to. If the package listens to JobProcessing/JobProcessed, jobs dispatched inside a DB::transaction() may log statuses for work that gets rolled back. Dispatch after commit (afterCommit on the job or DB::afterCommit) where correctness matters.
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.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast