Queue Jobs¶
GeneratePdfJob 將 PDF 生成任務排入背景處理,避免阻塞 HTTP 請求週期。套件提供與 CodeIgniter Tasks(codeigniter4/tasks)及主流第三方佇列套件(如 codeigniter4-queue)的整合介面。
PHP Compatibility
This example uses PHP 8.5 syntax. If your environment runs PHP 8.1 or 7.4, use NextPDF Backport for a backward-compatible build.
基本架構¶
HTTP 請求
└─▶ 推送任務至佇列 (Redis/Database)
└─▶ Worker 程序
└─▶ GeneratePdfJob::execute()
├─▶ pdf_document() 生成 PDF
├─▶ 儲存至 writable/ 或雲端
└─▶ 觸發完成回調
建立自訂 PDF Job¶
繼承 GeneratePdfJob 抽象類別:
<?php
declare(strict_types=1);
namespace App\Jobs;
use NextPDF\CodeIgniter\Jobs\GeneratePdfJob;
use NextPDF\Core\Document;
final class GenerateInvoicePdfJob extends GeneratePdfJob
{
public function __construct(
private readonly int $invoiceId,
) {}
/**
* 建構 PDF 文件。
*/
protected function buildDocument(Document $document): void
{
$invoice = model('InvoiceModel')->find($this->invoiceId);
$document->addPage();
$document->text("Invoice #{$invoice->id}", x: 20, y: 30, fontSize: 20);
$document->text("Customer: {$invoice->customer_name}", x: 20, y: 50);
$document->text("Amount: \${$invoice->total}", x: 20, y: 70);
}
/**
* PDF 生成成功後的回調。
*
* @param non-empty-string $pdfBytes
*/
protected function onSuccess(string $pdfBytes): void
{
$path = WRITEPATH . "uploads/invoices/invoice-{$this->invoiceId}.pdf";
file_put_contents($path, $pdfBytes);
// 更新資料庫紀錄
model('InvoiceModel')->update($this->invoiceId, [
'pdf_path' => $path,
'pdf_ready_at' => date('Y-m-d H:i:s'),
]);
}
/**
* PDF 生成失敗時的回調。
*/
protected function onFailure(\Throwable $e): void
{
log_message('error', "Invoice PDF generation failed: {$e->getMessage()}", [
'invoice_id' => $this->invoiceId,
]);
}
}
與 codeigniter4/tasks 整合¶
若使用官方 CI4 Tasks 套件進行排程:
<?php
declare(strict_types=1);
namespace Config;
use CodeIgniter\Tasks\Config\Tasks as BaseTask;
final class Tasks extends BaseTask
{
public function run(): void
{
// 每日凌晨 2 點批次生成月結報告
$this->call(function () {
$pendingInvoices = model('InvoiceModel')->where('pdf_ready_at', null)->findAll();
foreach ($pendingInvoices as $invoice) {
(new \App\Jobs\GenerateInvoicePdfJob($invoice->id))->execute();
}
})->daily('02:00');
}
}
與 codeigniter4-queue 整合¶
若使用 lonnieezell/codeigniter-queue 等第三方佇列套件:
// 推送至佇列
$queue = service('queue');
$queue->push('pdf', 'generate_invoice', [
'job_class' => \App\Jobs\GenerateInvoicePdfJob::class,
'invoice_id' => $invoiceId,
]);
<?php
declare(strict_types=1);
namespace App\Jobs;
use NextPDF\CodeIgniter\Jobs\GeneratePdfJob;
// 實作第三方佇列套件的 Job 介面
final class QueueableInvoicePdfJob extends GeneratePdfJob implements \Queue\JobInterface
{
public function execute(array $data): bool
{
$this->invoiceId = $data['invoice_id'];
return parent::run(); // 呼叫 GeneratePdfJob 的執行邏輯
}
}
重試機制¶
final class GenerateInvoicePdfJob extends GeneratePdfJob
{
// 最大重試次數
protected int $maxRetries = 3;
// 重試延遲(秒,指數退避)
protected array $retryDelays = [30, 120, 300];
// 應觸發重試的例外類型
protected array $retryOn = [
\NextPDF\Core\Exception\RenderingException::class,
];
}
進度回報¶
對於多頁長文件,可透過資料庫或快取回報生成進度:
protected function buildDocument(Document $document): void
{
$pages = $this->getPageData();
$total = count($pages);
foreach ($pages as $index => $pageData) {
$document->addPage();
$document->text($pageData['content'], x: 20, y: 30);
// 每 10 頁更新一次進度
if ($index % 10 === 0) {
cache()->save(
"pdf_progress_{$this->jobId}",
['processed' => $index + 1, 'total' => $total],
300, // TTL 5 分鐘
);
}
}
}
CLI Worker 啟動¶
# 使用 spark 指令啟動 Worker(若使用 CI4 Tasks)
php spark tasks:run
# 使用 Supervisor 管理 Worker(生產環境建議)
# /etc/supervisor/conf.d/nextpdf-worker.conf
[program:nextpdf-worker]
command=php /var/www/html/spark tasks:run
directory=/var/www/html
autostart=true
autorestart=true
numprocs=2
stderr_logfile=/var/log/nextpdf-worker.err.log
stdout_logfile=/var/log/nextpdf-worker.out.log
參見¶
- CodeIgniter 套件總覽 — 套件功能概覽
- Services 與 Helpers — 同步 PDF 生成