跳轉到

Worker 模式指南

架構概觀

┌─────────────────────────────────────────────────┐
│  程序級別(啟動時初始化一次)                      │
│  ┌─────────────────┐  ┌─────────────────────┐   │
│  │  FontRegistry   │  │   ImageRegistry     │   │
│  │  (字型索引)    │  │   (圖像快取)       │   │
│  └────────┬────────┘  └──────────┬──────────┘   │
│           └──────────┬───────────┘               │
│                 ┌────▼────────┐                  │
│                 │DocumentFactory│                 │
│                 └────┬────────┘                  │
└──────────────────────│──────────────────────────┘
                       │ 每個請求
         ┌─────────────┼─────────────┐
         ▼             ▼             ▼
    Document       Document       Document
    (可棄式)      (可棄式)      (可棄式)

基本設定

use NextPDF\Core\DocumentFactory;
use NextPDF\Core\Support\FontRegistry;
use NextPDF\Core\Support\ImageRegistry;
use NextPDF\Core\Accelerator\SpectrumClient;

// === 程序啟動時執行一次 ===
$fontRegistry = FontRegistry::create()
    ->registerDirectory('/fonts/system')
    ->registerFont(path: '/fonts/custom/NotoSansCJKtc.otf', alias: 'NotoSansCJKtc');

$imageRegistry = ImageRegistry::create()
    ->withCacheSize(maxEntries: 100);

$spectrum = SpectrumClient::create();  // 可選,Rust 加速

$factory = DocumentFactory::create(
    fontRegistry:  $fontRegistry,
    imageRegistry: $imageRegistry,
    accelerator:   $spectrum,           // 可選
);

// === 每個請求 ===
function handleRequest(DocumentFactory $factory): void
{
    $document = $factory->make(pageSize: PageSize::A4);
    // ... 渲染內容 ...
    $document->save('/output/file.pdf');
    // $document 超出作用域後自動釋放
}

Laravel 整合

Service Provider 設定

// app/Providers/NextPdfServiceProvider.php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use NextPDF\Core\DocumentFactory;
use NextPDF\Core\Support\FontRegistry;
use NextPDF\Core\Support\ImageRegistry;

final class NextPdfServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(FontRegistry::class, static function (): FontRegistry {
            return FontRegistry::create()
                ->registerDirectory(config('nextpdf.fonts_path'));
        });

        $this->app->singleton(ImageRegistry::class, static function (): ImageRegistry {
            return ImageRegistry::create();
        });

        $this->app->singleton(DocumentFactory::class, static function ($app): DocumentFactory {
            return DocumentFactory::create(
                fontRegistry:  $app->make(FontRegistry::class),
                imageRegistry: $app->make(ImageRegistry::class),
            );
        });
    }
}

Laravel Octane 整合

// config/octane.php
return [
    'warm' => [
        \NextPDF\Core\DocumentFactory::class,  // 在 Octane 啟動時預熱
    ],
    'flush' => [
        // DocumentFactory 不需要 flush,Registry 設計為執行緒安全
    ],
];

Symfony 整合

# config/services.yaml
services:
    NextPDF\Core\Support\FontRegistry:
        factory: ['NextPDF\Core\Support\FontRegistry', 'create']
        calls:
            - registerDirectory: ['%kernel.project_dir%/fonts']
        shared: true

    NextPDF\Core\DocumentFactory:
        factory: ['NextPDF\Core\DocumentFactory', 'create']
        arguments:
            $fontRegistry: '@NextPDF\Core\Support\FontRegistry'
            $imageRegistry: '@NextPDF\Core\Support\ImageRegistry'
        shared: true

佇列工作(Queue Workers)

// Laravel Job
final class GeneratePdfJob implements ShouldQueue
{
    public function __construct(
        private readonly string $templateId,
        private readonly array  $data,
    ) {}

    public function handle(DocumentFactory $factory): void
    {
        $document = $factory->make(pageSize: PageSize::A4);
        // ... 渲染 ...
        $document->save(storage_path("pdfs/{$this->templateId}.pdf"));
    }
}

並發控制

Cloudflare Workers

use NextPDF\Cloudflare\CloudflareDocumentFactory;

// Cloudflare Workers 使用特殊工廠(無 FFI 依賴)
$factory = CloudflareDocumentFactory::create(
    fontsBaseUrl: 'https://assets.example.com/fonts',
);

監控與可觀測性

延伸閱讀