Serverless-обработка PDF: генерация, извлечение и трансформация
Генерируйте PDF из HTML-шаблонов или данных, извлекайте текст и структурированные данные из загруженных документов и трансформируйте PDF в шагах фонового пайплайна — без HTTP-таймаута, с поддержкой бинарных ответов и встроенными ретраями.
Обновлено: 2026-06-28
Кратко
Суть ответа
Serverless-обработка PDF: генерация, извлечение и трансформация. HTTP-обработчик принимает запрос на генерацию или извлечение, возвращает 202 с ID задачи и запускает шаг пайплайна. Шаг выполняет тяжёлую PDF-операцию с собственным бюджетом памяти, ретраится при сбое и сохраняет результат в объектное хранилище.
Когда подходит
- Генерация счетов и отчётов, которая занимает больше секунды
- Извлечение данных из документов и OCR в фоновых пайплайнах
- Пакетная генерация PDF (N счетов, N отчётов) с параллельным fan-out
На что обратить внимание
- PDF-библиотеки (pdf-lib, pdfkit, puppeteer для HTML-в-PDF) требовательны к памяти. Генерация 10 PDF параллельно в одном вызове обработчика может исчерпать память на ограниченных serverless-рантаймах.
- Без ретрая при сбое временное падение библиотеки или OOM во время генерации теряет задачу целиком. Пользователь получает ошибку и вынужден повторять вручную.
Нагрузка и где ломается
Почему обработка PDF не помещается в синхронный HTTP
- Генерация PDF из сложных шаблонов занимает 2–30 секунд — упирается в таймауты шлюза
- Извлечение текста из загруженных PDF с OCR может занимать минуты на файлах с большим числом изображений
- Бинарные ответы (base64-кодирование больших PDF) добавляют давление на память синхронных обработчиков
Разброс задержек у PDF-операций широкий: простой одностраничный счёт может сгенерироваться за 500 мс, но 50-страничный отчёт с графиками, 100-страничный контракт с OCR или пачка из 200 счетов не укладываются в окно синхронного обработчика.
Когда простых рецептов недостаточно
Почему генерация PDF внутри HTTP-обработчика хрупка
PDF-библиотеки (pdf-lib, pdfkit, puppeteer для HTML-в-PDF) требовательны к памяти. Генерация 10 PDF параллельно в одном вызове обработчика может исчерпать память на ограниченных serverless-рантаймах.
Без ретрая при сбое временное падение библиотеки или OOM во время генерации теряет задачу целиком. Пользователь получает ошибку и вынужден повторять вручную.
Как помогает Inquir
PDF-операции как шаги async-пайплайна
HTTP-обработчик принимает запрос на генерацию или извлечение, возвращает 202 с ID задачи и запускает шаг пайплайна. Шаг выполняет тяжёлую PDF-операцию с собственным бюджетом памяти, ретраится при сбое и сохраняет результат в объектное хранилище.
Бинарные PDF сохраняются в объектное хранилище (S3-совместимое), а клиент получает pre-signed URL — вместо большого base64-тела через шлюз.
Что вы получаете
Паттерны serverless-обработки PDF
Генерация PDF из шаблона
Отрендерите HTML-шаблон с данными, сконвертируйте в PDF через puppeteer или PDF-библиотеку, сохраните в объектное хранилище, верните pre-signed URL.
Извлечение текста из PDF
Извлекайте текст и структурированные данные из загруженных PDF — счетов, контрактов, форм. Возвращайте структурированный JSON для дальнейшей обработки.
Пакетная генерация PDF
Генерируйте N PDF в параллельных шагах пайплайна (fan-out), затем объединяйте или упаковывайте в zip в финальном шаге (fan-in). 200 счетов — за минуты, а не часы.
OCR для PDF с изображениями
Шаг пайплайна вызывает OCR-сервис или локальную библиотеку (tesseract в Python) для извлечения текста из сканов — долгая операция с ретраями при сбое.
Что дальше
Поток async-генерации PDF
HTTP-обработчик возвращает 202 + ID задачи
Проверьте запрос, сохраните запись задачи со status=pending, запустите пайплайн с данными и ID задачи.
Шаг пайплайна генерирует PDF
Отрендерите шаблон с данными, сгенерируйте PDF, загрузите в объектное хранилище, запишите URL файла в запись задачи.
Уведомить клиента
Верните pre-signed URL для скачивания через вебхук, письмо или опрос эндпоинта статуса.
Пример кода
Пайплайн генерации PDF-счёта
HTTP-обработчик ставит работу через global.durable.startNew, который запускает рендерер как durable-инстанс; эта функция рендерит HTML в PDF, загружает его в объектное хранилище и обновляет запись задачи. Инстанс переживает рестарты и адресуется по id для опроса статуса.
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' }) }; }
import puppeteer from 'puppeteer-core'; export async function handler(event) { const { invoiceId, customerId } = event; // the input passed to startNew() 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 }; }
Когда подходит
Используйте serverless-обработку PDF для
Когда это уместно
- Генерация счетов и отчётов, которая занимает больше секунды
- Извлечение данных из документов и OCR в фоновых пайплайнах
- Пакетная генерация PDF (N счетов, N отчётов) с параллельным fan-out
Когда лучше выбрать другое
- Простые одностраничные PDF, которые стабильно генерируются быстрее 1 секунды, — оставьте их синхронными, так проще
Частые вопросы
Частые вопросы
Как отдавать большие бинарные PDF?
Сохраняйте PDF в объектное хранилище (S3-совместимое) и возвращайте pre-signed URL для скачивания. Не передавайте большие base64-PDF в теле HTTP-ответа — ссылки на хранилище берегут и лимиты шлюза, и память клиента.
Можно ли использовать Python-библиотеки вроде reportlab или pdfplumber?
Да — Python 3.12 поддерживает reportlab, pdfplumber, PyMuPDF и другие PDF-библиотеки. Задеплойте Python-функцию для извлечения и трансформации рядом с Node.js-функциями для HTTP-обработчиков в том же воркспейсе.