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 Failed Job Monitor Laravel Package

spatie/laravel-failed-job-monitor

Spatie's Laravel Failed Job Monitor sends notifications when a queued job fails. It uses Laravel's native notification system and can alert via mail or Slack, with configuration for enabled status, channels, email addresses, and Slack webhook URL.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • Extremely thin integration surface: the package registers a listener on Laravel's native Illuminate\Queue\Events\JobFailed event and dispatches a Laravel notification. It introduces no new persistence, no new infrastructure, and no queue/driver coupling — it works with any Laravel queue backend (Redis, SQS, database, sync) and with Horizon.
  • It rides on existing platform primitives (event dispatcher, notification system, mail transport, Slack webhook), so it inherits our existing mail/Slack credential management and secrets handling rather than creating a parallel alerting path.
  • Scope is deliberately narrow: it is a point failure notifier, not an observability tool. It does not measure queue depth, throughput, latency, or failure rate, and it provides no dashboard or API. It complements Horizon/APM; it does not replace them.
  • Extensibility is the real architectural lever: notification and notifiable are config-swappable classes, so we can route to PagerDuty/Opsgenie/Teams via a community or in-house notification channel without forking.

Integration feasibility

  • Installation is composer require + vendor:publish + four env vars — an afternoon of work, not a project. PHP 8+ and Laravel 9–13 are supported by current 4.x releases; the enabled flag (4.5.0) makes it safe to ship the same config to every environment and disable locally/CI.
  • Slack requires guzzlehttp/guzzle, which is already a transitive dependency in nearly all Laravel apps; effectively a no-op.
  • One non-obvious integration gate: notificationFilter closures break php artisan config:cache (LogicException: Your configuration files are not serializable). Any production deployment that caches config must use a static callable class. This must be in the implementation checklist, not discovered in a deploy pipeline.
  • FAILED_JOB_CHANNELS and FAILED_JOB_EMAILS are comma-split env strings — acceptable, but they mean alert routing lives in env vars, not in code review or a config management system. For anything on-call-critical this is a governance smell.

Technical risk

  • Low dependency risk: MIT, Spatie-maintained, ~1k stars, releases through Laravel 13, clean changelog history back to 1.0.0. Dependents: 0 in the supplied metadata is almost certainly an indexing artifact and should not be read as adoption risk.
  • Medium — alert storms. There is no deduplication, aggregation, throttling, or backoff. A systemic failure (broker outage, bad deploy, DB saturation) fails every job in flight and produces one notification per failed job. At even modest volume this saturates Slack webhooks (HTTP 429) and mail sending quotas and, more importantly, trains on-call to ignore the channel. This is the single largest operational hazard and it is a configuration/design problem, not a package bug.
  • Medium — silent monitor failure. Nothing monitors the monitor. A wrong webhook, revoked SMTP credential, or a JobFailed listener that throws leaves you with a false sense of coverage and no signal that coverage is gone.
  • Low/Medium — synchronous send path. Notifications are dispatched inline from the failed-job event handler inside the worker. If the default notification is not ShouldQueue, a slow or hanging Slack/webhook call blocks the worker loop after every failure — exactly when the system is already unhealthy. Verify and, if needed, supply a queued custom notification.
  • Low vendor lock-in: config + one composer line is fully reversible.

Key questions

  • What is our current failed-job detection story (Horizon notifications, Sentry/Bugsnag, APM, nothing)? Are we closing a gap or adding a fourth overlapping channel?
  • Which queues are high-volume or storm-prone, and do we need per-queue routing (e.g., critical → page, bulk → digest channel)?
  • Is the notification queued, and what is the acceptable latency from job failure to human notification?
  • Who is the paging target, and does the team's incident tooling accept a generic Laravel notification, or do we need a custom notifiable/channel to reach PagerDuty/Opsgenie?
  • Do we have a mechanism to prove the monitor works (synthetic canary job) and an owner accountable for that check?

Integration Approach

Stack fit

  • Native fit for any Laravel 9+ / PHP 8+ service running queued jobs. Zero fit for non-Laravel services in the estate — those need a separate path (APM alerting, log-based alerting), which argues for treating this as a Laravel-tier solution inside a broader alerting standard rather than the standard itself.
  • Natural pairing with Horizon: 4.3.1+ embeds an "open in Horizon" action in the notification, which materially shortens mean-time-to-diagnosis for on-call.

Migration path

  • Greenfield for most teams: there is no incumbent to migrate off. If Horizon failed-job notifications or a Sentry integration already exists, run both in parallel for a sprint, compare signal-to-noise, then retire one. Avoid running three.
  • No data migration, no schema change, no downtime. Rollback is removing the listener/config and the composer line — instantaneous.

Compatibility

  • Pin to ^4.x and validate against the app's Laravel/PHP matrix at install time; the package tracks new Laravel majors with some lag, so treat it as an item on every framework-upgrade checklist rather than an assumption.
  • Must verify php artisan config:cache succeeds post-integration with the filter class (not closure) in place — make this an explicit acceptance criterion in the PR.
  • Confirm the app's notification channel config (mailer, Slack webhook) is already exercised in production; the package will not surface a broken mailer, it will just fail quietly.

Sequencing

  1. Week 0 — Discovery: inventory existing failed-job alerting per service; decide consolidation target; pick channels and routing rules.
  2. Week 1 — Build: install, publish config, replace any closure filter with a static callable class, decide queued vs. inline notification, add FAILED_JOB_* envs to staging only.
  3. Week 1 — Prove it: dispatch a deliberately failing job in staging for each target channel; confirm receipt and content (job class, exception, Horizon link). Capture as a repeatable smoke test.
  4. Week 2 — Production pilot: enable on one mid-volume service, disabled-by-default for everything else. Observe noise for 5 business days.
  5. Week 2–3 — Noise tuning: implement notificationFilter by job class/queue to suppress known-flaky, non-actionable failures; establish storm handling (see below).
  6. Week 3 — Rollout: enable across Laravel services, publish runbook, hand off ownership. Add canary check to the on-call rotation.

Operational Impact

Maintenance

  • Near-zero steady-state: one composer dependency, one config file, no runtime services to operate. Realistic budget is a few hours per year, concentrated at framework-major upgrades.
  • The maintenance burden that does exist is alert hygiene, not code: routing lists, filter rules, and channel credentials drift and need a named owner and a quarterly review.

Support

  • MIT, community-supported via GitHub issues; no SLA, no vendor escalation path. Fine for a best-effort alerting aid; not acceptable as the sole paging mechanism for revenue-critical pipelines. Spatie does sell commercial support if that becomes a requirement.
  • Internal support is the real dependency: on-call must recognize the notification format and know the runbook. This is documentation work, not engineering.

Scaling

  • Scales trivially in the "number of services" dimension and poorly in the "number of failures" dimension. Cost and noise grow linearly with failure count because there is no aggregation.
  • Multi-team / multi-service routing requires a custom notifiable class (or per-service configs) — the default sends everything to one mailing list and one Slack webhook. That is workable for a single product team and becomes a bottleneck past roughly three owning teams.
  • No impact on job throughput under normal conditions; potential for measurable worker-loop delay under pathological failure rates if notifications are inline and the webhook is slow.

Failure modes

Mode Impact Mitigation
Alert storm from systemic outage Slack 429s, mail quota exhaustion, alert fatigue, missed real signals notificationFilter by job/queue, digest channel for bulk queues, route critical only to paging
Monitor silently broken (bad webhook/SMTP) False confidence, undetected coverage gap Scheduled synthetic canary job in staging+prod; alert on canary absence
Inline notification blocks worker Slower queue drain during incidents Use a ShouldQueue custom notification; confirm before rollout
Closure filter breaks config:cache Deploy pipeline failure Enforce static callable class; gate in CI
Package lag on new Laravel major Blocks framework upgrade Track as an upgrade-checklist dependency; have a one-line removal fallback
No aggregation means the same failure notified N times Noise, no signal on blast radius Complement with Horizon/APM failure-rate dashboards

Ramp-up

  • Engineering: ~2–4 hours end-to-end including staging verification. A Laravel-fluent developer needs no external help; the README is complete and current.
  • On-call/ops: ~30 minutes of runbook reading, provided the notification body carries the job class, queue, exception message, and a Horizon deep link — verify this in staging, because it is the difference between a 2-minute and a 20-minute triage.
  • Organizational: the only real ramp cost is agreeing where these alerts land and who owns them. Resolve that before enabling in production, not after the first storm.

TPM verdict: High-ROI, low-complexity gap-closer for Laravel services that currently have no failed-job notification, and a reasonable consolidation target if the team is running two or three overlapping ad-hoc alerts. It should be shipped as a first-line, best-effort notification layer — never as the sole paging path — with storm filtering and a canary designed in from day one. The package is not the risk; the unmanaged alert volume and the untested delivery path are.

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