Inquir Compute logoInquir Compute
Сценарий · Inquir Compute

Обработка PDF: async генерация и извлечение данных с объектным хранилищем

Puppeteer или pdfkit в Python: генерируйте PDF асинхронно, сохраняйте в S3, возвращайте pre-signed URL. Без HTTP-таймаута, без передачи бинаря в ответе.

Last updated: 2026-04-20

Direct answer

Обработка PDF: async генерация и извлечение данных с объектным хранилищем. HTTP-функция принимает параметры, возвращает `{ jobId }`. Пайплайн рендерит PDF (puppeteer в Node.js или reportlab в Python), загружает в S3, возвращает pre-signed URL.

When it fits

  • Генерация занимает > 2 секунд
  • Документ нужно хранить и скачивать несколько раз
  • Batch PDF generation (N invoices, N reports) with fan-out parallelism

Tradeoffs

  • Синхронная генерация с puppeteer в Lambda: cold start браузера + рендер HTML + сохранение = часто за пределами таймаута.
  • Встроить binary в JSON-ответ: base64 раздувает payload, клиент не может начать скачивание до получения всего тела.

Почему PDF-генерация ломается в HTTP

  • PDF generation from complex templates takes 2–30 seconds—hits gateway timeouts
  • Text extraction from uploaded PDFs with OCR can take minutes for image-heavy files
  • Binary response handling (base64 encoding large PDFs) adds memory pressure to synchronous handlers

Puppeteer или WeasyPrint занимают секунды. HTTP-ответ с PDF-файлом блокирует соединение на всё это время — таймаут шлюза ломает генерацию.

Где ломаются простые подходы

Синхронная генерация с puppeteer в Lambda: cold start браузера + рендер HTML + сохранение = часто за пределами таймаута.

Встроить binary в JSON-ответ: base64 раздувает payload, клиент не может начать скачивание до получения всего тела.

Async PDF на Inquir

HTTP-функция принимает параметры, возвращает `{ jobId }`. Пайплайн рендерит PDF (puppeteer в Node.js или reportlab в Python), загружает в S3, возвращает pre-signed URL.

Puppeteer через слой: нативный хром-бинарь доступен в контейнере Node.js 22 без custom Dockerfile.

Что нужно для надёжной PDF-обработки

Async split

HTTP возвращает jobId; пайплайн генерирует PDF вне HTTP-окна.

Объектное хранилище

PDF сохраняется в S3/GCS; клиент получает pre-signed URL — не бинарный blob в ответе.

Нативные зависимости через слои

Puppeteer, chromium, reportlab, WeasyPrint через слои без Dockerfile.

Traceability

jobId → история прогона с логами каждого шага; проще дебажить ошибки рендера.

Как организовать PDF-генерацию

1

Принять запрос, вернуть jobId

HTTP-функция валидирует параметры, запускает `global.durable.startNew()`, возвращает `{ jobId }` за <100 мс.

2

Сгенерировать PDF в пайплайне

Puppeteer рендерит HTML или reportlab строит документ. Сохранить в S3.

3

Вернуть pre-signed URL

Пайплайн сохраняет URL в БД или отправляет вебхук. Клиент получает ссылку и скачивает напрямую из S3.

Invoice PDF generation pipeline

HTTP handler triggers async generation; pipeline step renders HTML to PDF, uploads, and notifies. Client polls job status.

api/generate-invoice.mjs (HTTP handler)
export async function handler(event) {
  const { invoiceId, customerId } = JSON.parse(event.body || '{}');
  if (!invoiceId) return { statusCode: 400, body: JSON.stringify({ error: 'invoiceId required' }) };
  const existing = await db.invoicePdfs.find(invoiceId);
  if (existing?.url) return { statusCode: 200, body: JSON.stringify({ url: existing.url }) };
  await global.durable.startNew('render-invoice-pdf', undefined, { invoiceId, customerId });
  return { statusCode: 202, body: JSON.stringify({ invoiceId, status: 'generating' }) };
}
jobs/render-invoice-pdf.mjs (pipeline step)
import puppeteer from 'puppeteer-core';

export async function handler(event) {
  const { invoiceId, customerId } = event.payload ?? {};
  const invoice = await db.invoices.findById(invoiceId);
  const html = renderInvoiceTemplate(invoice);
  const browser = await puppeteer.launch({ executablePath: '/usr/bin/chromium' });
  const page = await browser.newPage();
  await page.setContent(html, { waitUntil: 'networkidle0' });
  const pdfBytes = await page.pdf({ format: 'A4', printBackground: true });
  await browser.close();
  const url = await storage.upload(pdfBytes, `invoices/${invoiceId}.pdf`);
  await db.invoicePdfs.upsert({ invoiceId, url, generatedAt: new Date() });
  return { invoiceId, url };
}

Когда нужен async PDF

Когда это уместно

  • Генерация занимает > 2 секунд
  • Документ нужно хранить и скачивать несколько раз
  • Batch PDF generation (N invoices, N reports) with fan-out parallelism

Когда лучше не трогать

  • Простой text/plain-to-PDF < 1 страницы без изображений — sync достаточно

Вопросы и ответы

Как добавить Puppeteer в Inquir?

Слой с puppeteer-core + chromium-min; подключить к Node.js 22 функции. Puppeteer доступен через `import puppeteer from "puppeteer-core"`.

Python или Node.js для PDF?

Node.js: puppeteer для HTML-рендера. Python: reportlab или WeasyPrint для программной генерации. Оба через слои.

Inquir Compute logoInquir Compute

Самый простой способ запускать AI-агентов и backend-джобы без инфраструктуры.

Связаться info@inquir.org

© 2025 Inquir Compute. Все права защищены.