spatie/laravel-discord-alerts
Quickly send alerts to Discord from your Laravel app using a simple facade. Messages are dispatched via a queued job, so your app keeps running even if Discord is down. Just set a webhook URL and start notifying yourself of noteworthy events.
Architecture fit
DiscordAlert::message()) that serialises a payload and dispatches SendToDiscordChannelJob to a queue. It is not a notification framework, not a Discord SDK, and not an incident-management system. Scope it accordingly.DISCORD_ALERT_WEBHOOK). No database migrations, no schema changes, no long-running daemons.Http::post() in a controller or model observer.Notification + Notifiable abstraction should win; this package is for internal/ops signalling only.Integration feasibility
attach() path-based, attachData() in-memory), multi-webhook routing via to(), per-message username/avatar/TTS overrides, and delayMinutes() / delayHours() deferral.Technical risk
retry_after. A rate-limit storm will show up as failed jobs, not as throttled backoff. This is the single biggest technical risk for high-volume use.attach() path files must still exist when the worker runs, and that cross-machine workers need attachData(). On ephemeral or per-node filesystems this silently produces failed sends. This is an operational trap, not a technical bug.config:cache. Rotation requires a deploy or config clear — plan a dual-webhook cutover.DiscordAlert::fake()-style assertion helper. Verify this before committing — otherwise alert-emitting code paths will be untested or will hit the network in CI.Key questions
composer.json actually constrain? Changelog evidence only confirms Laravel 9 and 10. Confirm 11/12 before assuming a current-stack fit.retry_after? Read SendToDiscordChannelJob source.Http?attach() is off-limits.Stack fit
QUEUE_CONNECTION=sync, the package's core benefit evaporates — the HTTP call becomes synchronous and Discord latency/failures hit the request path. Confirm the driver before adopting.queue_connection and queue (env-driven, DISCORD_ALERT_QUEUE_CONNECTION / DISCORD_ALERT_QUEUE), so alerts can be isolated onto a dedicated queue rather than competing with business jobs. Use this.Migration path
Http::post() calls: low-risk mechanical swap. Keep the old call sites behind a thin internal OpsAlert wrapper class that delegates to the facade. That wrapper is the seam that makes the eventual replacement (or a fork) a one-file change.Spatie\DiscordAlerts\Facades\DiscordAlert. Every call site should go through your own facade/service so vendor churn, config reshaping, or a switch to a different transport is contained.Compatibility
Sequencing
#ops-test channel, one call site, verify queue dispatch, verify failure behaviour with a deliberately bad URL.job config key to set $tries, $backoff, and $timeout; add logging on failed(); document the secrets/rotation runbook.failed_jobs is monitored.marketing, infra, etc.), route by audience. Keep one channel per team to stay under per-webhook rate limits.Maintenance
Support
Scaling
delayMinutes() to spread bursts.Failure modes
| Failure | Symptom | Mitigation |
|---|---|---|
| Discord down / 5xx | Alerts silently queued then failed | Configure $tries/$backoff on a custom job; alert on failed_jobs growth |
| Rate limited (429) | Failed jobs, dropped alerts | Aggregate messages; one webhook per audience; verify retry_after handling |
| Worker never running | Alerts queue indefinitely, no error | Monitor queue depth and worker heartbeats independently of this package |
attach() path missing on worker |
Failed job, no delivery | Standardise on attachData(); forbid path-based attach via code review |
| Webhook rotated/revoked | 401/404, all sends fail | Dual-webhook cutover; config-cache clear in the deploy; smoke test post-deploy |
| Secrets in config cache | Rotated value not picked up | Explicit config:clear step; treat webhook URL as a rotated secret |
| Channel deleted | Silent loss of the alert destination | Periodic synthetic heartbeat alert to each channel |
Ramp-up
How can I help you explore Laravel packages today?