Weave Code
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

Send instant notifications when Laravel queued jobs fail. Uses Laravel’s notification system with built-in Mail and Slack support, configurable via env/config, and easy install/publish. Great for monitoring production queues and alerting the right people.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/laravel-failed-job-monitor
    php artisan vendor:publish --tag=failed-job-monitor-config
    
  2. Configure .env:

    FAILED_JOB_MONITOR_ENABLED=true
    FAILED_JOB_CHANNELS=mail,slack
    FAILED_JOB_EMAILS=admin@example.com
    FAILED_JOB_SLACK_WEBHOOK_URL=https://hooks.slack.com/...
    
  3. First Use Case: Dispatch a job that may fail (e.g., SendEmailJob). If it fails, the package will automatically trigger notifications via configured channels (mail/Slack).


Implementation Patterns

Core Workflow

  1. Job Dispatch:

    dispatch(new SendEmailJob($user));
    
    • The package hooks into Laravel’s FailedJob event via a service provider.
  2. Notification Customization:

    • Extend Default Notification:
      // app/Notifications/CustomFailedJobNotification.php
      use Spatie\FailedJobMonitor\Notification;
      
      class CustomFailedJobNotification extends Notification {
          public function toMail($notifiable) {
              return (new MailMessage)
                  ->subject('Job Failed: ' . $this->failedJob->job)
                  ->line('The job failed with exception: ' . $this->failedJob->exception);
          }
      }
      
      Update config:
      'notification' => \App\Notifications\CustomFailedJobNotification::class,
      
  3. Dynamic Recipients:

    • Use a custom Notifiable class to fetch recipients dynamically (e.g., from a database):
      // app/Notifiables/CustomFailedJobNotifiable.php
      class CustomFailedJobNotifiable implements ShouldQueue {
          public function route($notifiable, $notification) {
              return ['email' => $this->getAdminEmail()];
          }
      }
      
      Update config:
      'notifiable' => \App\Notifiables\CustomFailedJobNotifiable::class,
      
  4. Filtering Notifications:

    • Skip notifications for specific jobs/exceptions:
      // app/Notifications/FailedJobFilter.php
      class FailedJobFilter {
          public static function filter(Spatie\FailedJobMonitor\Notification $notification): bool {
              return !in_array($notification->failedJob->job, ['SendWelcomeEmailJob']);
          }
      }
      
      Update config:
      'notificationFilter' => [\App\Notifications\FailedJobFilter::class, 'filter'],
      
  5. Environment-Specific Config:

    • Disable in local environments:
      FAILED_JOB_MONITOR_ENABLED=${APP_ENV !== 'local'}
      

Integration Tips

  • Horizon Integration:

    • The package automatically includes a link to Horizon if installed (horizon:failed-jobs).
    • Customize the link in your notification’s toMail method:
      ->action('View in Horizon', url(config('horizon.path').'/failed-jobs'));
      
  • Slack Rich Messages:

    • Enhance Slack notifications with attachments:
      public function toSlack($notifiable, array $data) {
          return [
              'text' => "Job failed: {$this->failedJob->job}",
              'attachments' => [
                  [
                      'title' => 'Exception',
                      'text' => $this->failedJob->exception,
                      'color' => '#ff0000',
                  ],
              ],
          ];
      }
      
  • Rate Limiting:

    • Combine with throttle middleware to avoid notification spam:
      // app/Http/Middleware/ThrottleFailedJobs.php
      public function handle($request, Closure $next) {
          return $next($request)->throttle([
              'failed_job_notifications' => 1,
              'perMinute' => 5,
          ]);
      }
      

Gotchas and Tips

Pitfalls

  1. Configuration Caching:

    • Avoid using closures in notificationFilter (not serializable). Use static methods in classes instead.
    • Fix: Replace:
      'notificationFilter' => fn($notification) => true,
      
      With:
      'notificationFilter' => [\App\Filters\JobFilter::class, 'shouldNotify'],
      
  2. Exception Handling:

    • The package catches exceptions during notification delivery. Log these separately:
      try {
          $notification->send($notifiable);
      } catch (\Exception $e) {
          Log::error('Failed to send job failure notification', ['exception' => $e]);
      }
      
  3. Queue Workers:

    • Ensure your queue workers have access to the .env file (e.g., php artisan queue:work --env=production).
  4. Horizon-Specific Issues:

    • If Horizon is missing, the package gracefully hides the "View in Horizon" link (no errors thrown).

Debugging Tips

  1. Verify Failed Jobs:

    • Check the failed_jobs table for pending notifications:
      SELECT * FROM failed_jobs WHERE failed_at > NOW() - INTERVAL 1 HOUR;
      
  2. Log Notifications:

    • Add debug logs in your custom notification class:
      Log::debug('Sending notification for job', [
          'job' => $this->failedJob->job,
          'exception' => $this->failedJob->exception,
      ]);
      
  3. Test Locally:

    • Force a job failure in phpunit.xml:
      <env key="FAILED_JOB_MONITOR_ENABLED" value="true"/>
      <env key="MAIL_MAILER" value="log"/>
      

Extension Points

  1. Custom Channels:

    • Add support for new channels (e.g., PagerDuty, SMS) by extending the Notification class:
      public function via($notifiable) {
          return ['mail', 'pagerduty'];
      }
      
  2. Dynamic Job Filtering:

    • Use job metadata (e.g., tags) to filter notifications:
      public static function filter(Notification $notification): bool {
          return $notification->failedJob->payload['data']['priority'] === 'high';
      }
      
  3. Retries:

    • Implement a retry mechanism for failed notifications:
      if (!$notification->send($notifiable)) {
          $notifiable->failed($notification);
          // Requeue after delay
          $notifiable->queueAfter(5);
      }
      
  4. Template Overrides:

    • Customize the email template by publishing views:
      php artisan vendor:publish --tag=failed-job-monitor-views
      
      Override resources/views/vendor/failed-job-monitor/email.blade.php.

Pro Tips

  • Environment-Specific Recipients:

    'mail' => [
        'to' => env('FAILED_JOB_EMAILS', 'admin@example.com'),
        'cc' => env('FAILED_JOB_CC_EMAILS', 'team@example.com'),
    ],
    
  • Slack Formatting: Use Slack’s block kit for rich notifications:

    public function toSlack($notifiable) {
        return [
            'blocks' => [
                [
                    'type' => 'section',
                    'text' => [
                        'type' => 'mrkdwn',
                        'text' => '*Job Failed* :rotating_light:',
                    ],
                ],
                [
                    'type' => 'section',
                    'fields' => [
                        ['type' => 'mrkdwn', 'text' => '*Job*', 'value' => $this->failedJob->job],
                        ['type' => 'mrkdwn', 'text' => '*Exception*', 'value' => $this->failedJob->exception],
                    ],
                ],
            ],
        ];
    }
    
  • Monitoring: Track notification delivery failures in Sentry or Laravel’s listeners log:

    try {
        $notification->send($notifiable);
    } catch (\Exception $e) {
        Sentry::captureException($e);
    }
    
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.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai