Deck - Know when your background jobs fail before your customers do
by•
Background jobs fail silently. Horizon shows you what's running right now, but the history disappears with Redis. Deck remembers everything — every execution, searchable, with controls to cancel runaway jobs and block broken classes during incidents. Free open source package, hosted Cloud dashboard available.
Replies
Does Deck integrate with existing Horizon dashboards or does it fully replace them, and what happens to historical data when you first install it?
How does Deck handle retention if Redis itself is the bottleneck causing the failures in the first place, and does the cloud version have any storage limits on the job history?
@abdulkadir70837 Good question. Deck's execution log lives in your own database (Postgres/MySQL), not Redis, so it's fully independent of whatever's happening on the Redis side. If Redis itself is struggling, queue delays, memory pressure, connection issues, Deck still has visibility into whatever job data made it through, since recording happens at the worker level via Laravel's queue events, not by reading Redis internals.
That said, if Redis is bad enough that jobs aren't being dispatched or picked up at all, there's nothing to record yet, Deck can only see executions, it can't see what never got queued in the first place. That's actually one of the harder problems in this space: a job that's never dispatched can't be detected as "missing" the same way a job that started and stalled can be.
On Cloud storage limits: retention is tied to your plan, 90 days by default on self-hosted, configurable on Cloud based on your team's settings, with the ability to extend it. No hard cap on volume beyond the execution limits tied to pricing tiers.
How does Deck handle the storage growth over time as execution history piles up, is there any built-in pruning or do I need to manage retention myself?
@nebahatibcr There's built-in pruning, you don't have to manage it manually. Self-hosted, there's a deck:prune artisan command that deletes execution rows older than your configured retention_days (90 by default). You schedule it yourself, typically daily via Laravel's scheduler:
php
On Cloud, pruning happens automatically based on your team's retention settings, nothing to configure or run yourself.
One thing worth knowing if you're at real volume: for busy apps we recommend a dedicated database connection for Deck's tables, since it's writing a row per job execution, keeping that separate from your primary app database avoids adding pressure there as history accumulates.
Curious how the cancel and block controls actually work under the hood — does Deck need to wrap job dispatching, or can it intercept runs that were already dispatched before Deck was added?
@memetlepc No, Deck does not need to wrap job dispatching to cancel or block. The cancel-a-running-job and block-a-class controls work by interception at execution time — the worker checks a flag right before/while it runs each job. That means jobs that were already sitting on the queue before Deck was installed get caught the moment a Deck-equipped worker picks them up. The one capability that leans on dispatch-time involvement is removing a job that's still queued (cancel_pending), because that one needs the job's UUID to find it in the queue.
Finally someone fixed the "what ran last Tuesday at 3am" mystery. The search through old job executions already saved me from digging through logs during an incident.
The retroactive search across past job runs is such an underrated win for anyone who's ever lost an hour to "wait, did that batch actually finish". Catching it before it became another Redis casualty is sharp execution.
finally someone looked at horizon and said what we've all been thinking. the "block broken classes during incidents" detail is such a quiet lifesaver, exactly the kind of thing you only think about after a 3am outage.
@ogluzafer19806 Ha, exactly the origin story. That specific feature came out of one incident where I really wished I could just tell a job class "stop trying for the next hour" without touching a deploy pipeline at 3am. Once you've lived through that once, you build the button.
Appreciate you noticing it, it's easy to undersell in a feature list but it's honestly the one I use most myself.