Roy-Try-Catch
← Back to list

【Laravel】Queue + Horizon 完整實作 - 非同步任務與監控

Roy • Updated 2026-02-27 11:03:43

本篇介紹如何在 Laravel 框架中,使用 Queue 處理非同步任務,並搭配 Laravel Horizon 進行視覺化監控管理。

為什麼需要 Queue?

在 Web 應用中,有些任務不需要即時完成,例如:

  • 寄送 Email 通知
  • 圖片壓縮、影片轉檔
  • 呼叫第三方 API(如推播、簡訊)
  • 大量資料報表產生

若這些任務在 HTTP 請求中同步執行,會造成使用者等待時間過長。透過 Queue,可以將任務丟到背景執行,讓使用者立即獲得回應。

什麼是 Laravel Horizon?

Laravel Horizon 是 Laravel 官方的 Queue 監控工具,提供美觀的 Dashboard 介面,可以即時查看:

  • Queue 工作的執行狀況(待處理、執行中、失敗)
  • 處理速率(jobs/min)
  • 失敗任務的詳細錯誤訊息
  • 各 Queue 的 Worker 數量與資源消耗

安裝 Laravel Horizon

# 安裝套件
composer require laravel/horizon

# 發布設定與資源
php artisan horizon:install

執行後會產生:

  • config/horizon.php — Horizon 設定檔
  • public/vendor/horizon — Dashboard 前端資源

設定 Queue Connection

Horizon 需要使用 Redis 作為 Queue Driver:

# .env
QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

建立 Job

php artisan make:job SendWelcomeEmail
# app/Jobs/SendWelcomeEmail.php

派發 Job(Dispatch)

# Controller 中派發任務
use App\Jobs\SendWelcomeEmail;

class UserController extends Controller
{
 public function register(Request $request)
 {
 $user = User::create($request->validated());

 // 立即丟入 Queue
 SendWelcomeEmail::dispatch($user);

 // 延遲 5 分鐘後執行
 SendWelcomeEmail::dispatch($user)->delay(now()->addMinutes(5));

 // 指定丟到特定 Queue
 SendWelcomeEmail::dispatch($user)->onQueue('emails');

 return response()->json(['message' => '註冊成功']);
 }
}

設定 Horizon(config/horizon.php)

Horizon 的重點設定在於 environments,可以針對不同環境設定 Worker 數量與監控的 Queue:

# config/horizon.php
'environments' => [

 'production' => [
 'supervisor-1' => [
 'connection' => 'redis',
 'queue' => ['default', 'emails', 'notifications'],
 'balance' => 'auto', // 自動分配 Worker
 'minProcesses' => 1,
 'maxProcesses' => 10,
 'tries' => 3,
 'timeout' => 60,
 ],
 ],

 'local' => [
 'supervisor-1' => [
 'connection' => 'redis',
 'queue' => ['default', 'emails'],
 'balance' => 'simple',
 'processes' => 3,
 'tries' => 1,
 ],
 ],

],

balance 策略說明

策略 說明
simple 固定數量,平均分配到各 Queue
auto 依 Queue 積壓量自動動態調整 Worker 數
false 不做 balance,按設定的 Queue 順序處理

啟動 Horizon

# 啟動 Horizon(包含所有 Queue Worker)
php artisan horizon

# 暫停所有 Worker(不停止進程)
php artisan horizon:pause

# 繼續執行
php artisan horizon:continue

# 優雅終止(等待現有 Job 跑完後停止)
php artisan horizon:terminate

使用 Supervisor 管理 Horizon

正式環境必須用 Supervisor 讓 Horizon 常駐,確保重啟後自動恢復:

# /etc/supervisor/conf.d/horizon.conf
[program:horizon]
command=php /var/www/html/artisan horizon
numprocs=1
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/supervisor/horizon.log
stopwaitsecs=3600
supervisorctl reread
supervisorctl update
supervisorctl start horizo

注意:stopwaitsecs 建議設定比最長 Job timeout 還大,避免 Supervisor 強制 kill 掉正在執行中的 Job。

Horizon Dashboard 存取權限

預設 Horizon Dashboard 路由為 /horizon,在正式環境需要設定存取權限,避免公開:

# app/Providers/HorizonServiceProvider.php
use Laravel\Horizon\Horizon;

public function boot(): void
{
 parent::boot();

 Horizon::auth(function ($request) {
 // 只允許特定 Email 的使用者存取
 return in_array($request->user()?->email, [
 '[email protected]',
 ]);
 });
}

失敗任務處理

# 查看失敗任務清單
php artisan queue:failed

# 重新執行指定失敗任務(by ID)
php artisan queue:retry {id}

# 重新執行所有失敗任務
php artisan queue:retry all

# 清除所有失敗任務
php artisan queue:flush

Queue vs Horizon 差別

項目 queue:work Horizon
監控介面 有(Web Dashboard)
動態 Worker 調整 支援(auto balance)
Queue Driver 任意(database, redis...) 僅 Redis
適合環境 小型專案、簡單需求 中大型專案、需監控
指標統計 有(throughput, runtime)

小結

Laravel Queue 是處理耗時任務的標準解法,而 Laravel Horizon 則是讓你能夠「看見」Queue 運行狀況的利器。對於正式環境,強烈建議使用 Horizon + Supervisor 的組合,既有視覺化監控,也能保證服務的穩定性。

參考文獻:

https://laravel.com/docs/11.x/queues

https://laravel.com/docs/11.x/horizon

Comments

No comments yet.

請先登入