請求書 PDF の事前生成と初回 DL レイテンシ解消¶
- 作成日: 2026-05-21
- 目的: storefront 上の請求書ダウンロード初回レイテンシ(staging 実測 20 秒超)を、生成タイミングを注文確定時点へ前倒すことで構造的に解消する。
背景¶
ritsOrderInvoiceはReportInvoiceService.getOrIssueInitialInvoiceを経由し、保存済み PDF が無いと リクエストの内側で Playwright Chromium レンダリングを同期実行する仕組みになっている(packages/plugins/src/standard-extensions/report/report-invoice.service.ts)。- Chromium cold-start と
networkidle待ちで 20 秒の sync timeout に届く事例があり、staging では UI がstatus=GENERATINGメッセージへフォールバックする挙動が常態化していた。 - 元々は
OrderPlacedEventで invoice job を事前 enqueue する設計だったが、commit9e30553a7(SMILE 統合 PR)で「初回 DL 時の同期発行」へ切り替えられ、事前生成が停止していた。
決定¶
- 注文確定 (
OrderPlacedEvent) でReportQueueService.enqueueにより invoice job を事前投入する。worker process が請求書 PDF を非同期に生成し、R2 へ保存する。 - production: 専用
workerprocess group が処理する(apps/vendure-server/fly.toml)。 - staging:
VENDURE_RUN_JOB_QUEUE=trueの app machine 内で in-process worker が処理する(apps/vendure-server/fly.staging.toml)。 - 顧客の DL リクエストは保存済み PDF を返すだけの fast path になる。
- 既存仕様
2026-04-invoice-availability-regardless-of-payment-method.mdの「決済方法に依存せず請求書発行可能」要件はそのまま維持し、本決定はそのうちの 発行タイミング を前倒す変更に限定する。 - 同期発行 fallback (
ReportInvoiceService.getOrIssueInitialInvoiceの 20s sync wait) は救済路として残し、queue 未処理/backfill 未済の注文でも UI が壊れないようにする。
受け入れ条件¶
OrderPlacedEventが発火した注文について、worker がrits-report-generationqueue でtype: invoicejob を完了させ、report_recordに新規レコードを作成すること。- storefront の
ritsOrderInvoiceクエリが、通常の確定済み注文に対して 1 回目からstatus=READYと署名 URL を返却すること(worker 処理が完了済みであることが前提)。 - backfill スクリプト
apps/vendure-server/scripts/backfill-invoice-reports.tsで、対象状態(既定:PaymentSettled以降)の既存注文について、report_recordに未生成の invoice レコードを生成できること。 Sentry Metricsのvendure.report.job.enqueuedにtype=invoice, from_state=placed, to_state=placedが記録され、事前生成 lane が止まっていないかを継続観測できること。
非対象¶
- Chromium 以外のレンダラへの既定切り替え(
REPORT_RENDERER=cloudflare)。Cloudflare API token の Browser Rendering 権限付与が前提となるため、本仕様には含めず別 issue で扱う。 - 配送帳票 (
delivery/label) の発行タイミングと方式。 - 帳票テンプレートの内容変更。
- 再発行・訂正フロー。
運用¶
- backfill 実行例(staging):
flyctl ssh console --app ritsubi-ecommerce-staging \
-C "node --enable-source-maps dist/scripts/backfill-invoice-reports.js --limit 200"
ローカルから tsx 経由で実行する場合:
SECRETS_ENV=staging SECRETS_SERVICE=vendure ./scripts/ops/with-env.sh -- \
pnpm -C apps/vendure-server exec tsx scripts/backfill-invoice-reports.ts --dry-run
関連¶
docs/specifications/2026-04-invoice-availability-regardless-of-payment-method.mdpackages/plugins/src/standard-extensions/report/report-order.listener.tspackages/plugins/src/standard-extensions/report/report-invoice.service.tspackages/plugins/src/standard-extensions/report/report-queue.service.tsapps/vendure-server/scripts/backfill-invoice-reports.ts