Skip to content

队列任务

GeneratePdfJob 提供开箱即用的队列式 PDF 生成功能。对于耗时的文件,将工作交给后台工作者可以避免阻塞 HTTP 请求。

php
use Yeeefang\TcpdfNext\Laravel\Jobs\GeneratePdfJob;

派发任务

创建任务时传入一个闭包,该闭包接收 Document 实例并定义 PDF 的内容:

php
use Yeeefang\TcpdfNext\Laravel\Jobs\GeneratePdfJob;

GeneratePdfJob::dispatch(
    builder: function ($pdf) use ($report) {
        $pdf->setTitle($report->title)
            ->addPage()
            ->setFont('Helvetica', 'B', 16)
            ->cell(0, 10, $report->title)
            ->setFont('Helvetica', '', 11)
            ->multiCell(0, 6, $report->body);
    },
    outputPath: storage_path("app/reports/{$report->id}.pdf"),
);

成功与失败回调

通过 onSuccessonFailure 回调处理任务完成后的逻辑:

php
GeneratePdfJob::dispatch(
    builder: function ($pdf) use ($invoice) {
        $pdf->setTitle("发票 #{$invoice->number}")
            ->addPage()
            ->setFont('Helvetica', '', 12)
            ->cell(0, 10, "发票 #{$invoice->number}");
    },
    outputPath: storage_path("app/invoices/{$invoice->id}.pdf"),
    onSuccess: function (string $path) use ($invoice) {
        $invoice->update(['pdf_path' => $path, 'status' => 'ready']);
        Mail::to($invoice->customer)->send(new InvoiceReady($invoice));
    },
    onFailure: function (\Throwable $e) use ($invoice) {
        $invoice->update(['status' => 'generation_failed']);
        Log::error('PDF 生成失败', [
            'invoice' => $invoice->id,
            'error' => $e->getMessage(),
        ]);
    },
);

队列配置

指定队列名称、连接与延迟:

php
GeneratePdfJob::dispatch(
    builder: $builder,
    outputPath: $path,
)->onQueue('pdf-generation')
 ->onConnection('redis')
 ->delay(now()->addMinutes(5));

重试与超时

config/tcpdf-next.php 中设置默认值,或在派发时覆盖:

php
// config/tcpdf-next.php
'queue' => [
    'connection' => env('TCPDF_QUEUE_CONNECTION', 'redis'),
    'name'       => env('TCPDF_QUEUE_NAME', 'pdf-generation'),
    'tries'      => 3,
    'timeout'    => 120,
    'backoff'    => [10, 30, 60],
],

任务会使用指数退避策略:第一次重试等待 10 秒、第二次 30 秒、第三次 60 秒。

批量处理

使用 Laravel 的 Bus::batch() 同时生成多份 PDF:

php
use Illuminate\Support\Facades\Bus;
use Yeeefang\TcpdfNext\Laravel\Jobs\GeneratePdfJob;

$jobs = $invoices->map(fn (Invoice $invoice) => new GeneratePdfJob(
    builder: function ($pdf) use ($invoice) {
        $pdf->setTitle("发票 #{$invoice->number}")
            ->addPage()
            ->setFont('Helvetica', '', 12)
            ->cell(0, 10, "发票 #{$invoice->number}");
    },
    outputPath: storage_path("app/invoices/{$invoice->id}.pdf"),
));

Bus::batch($jobs)
    ->name('批量发票生成')
    ->onQueue('pdf-generation')
    ->allowFailures()
    ->then(function () {
        Log::info('所有发票 PDF 已生成完毕');
    })
    ->catch(function (\Throwable $e) {
        Log::error('部分发票生成失败', ['error' => $e->getMessage()]);
    })
    ->finally(function () {
        // 无论成败皆执行
        Notification::send($admins, new BatchCompleteNotification());
    })
    ->dispatch();

搭配 Blade 视图

结合 Blade 模板生成更复杂的 PDF:

php
GeneratePdfJob::dispatch(
    builder: function ($pdf) use ($order) {
        $html = view('pdf.order-confirmation', [
            'order' => $order,
            'items' => $order->items,
        ])->render();

        $pdf->setTitle("订单确认 #{$order->id}")
            ->writeHtml($html);
    },
    outputPath: storage_path("app/orders/{$order->id}.pdf"),
);

监控任务

使用 Laravel Horizon 或内置的 queue:monitor 指令追踪 PDF 队列状态:

bash
php artisan queue:monitor pdf-generation --max=100

下一步

以 LGPL-3.0-or-later 许可证发布。