Serverless-обработка CSV: парсинг, трансформация и загрузка больших файлов
Принимайте загрузку CSV по HTTP, сразу возвращайте 202 и обрабатывайте файл в фоновом пайплайне. Парсите миллионы строк, валидируйте и трансформируйте данные, делайте батчевый upsert с ключами идемпотентности и уведомляйте пользователей о завершении импорта — всё за пределами окна HTTP-таймаута.
Обновлено: 2026-06-28
Кратко
Суть ответа
Serverless-обработка CSV: парсинг, трансформация и загрузка больших файлов. HTTP-обработчик проверяет ссылку на файл (URL или ключ в хранилище), сохраняет метаданные задачи и возвращает 202 с ID задачи. Шаг пайплайна читает CSV по частям, делает идемпотентный upsert по ID строки и записывает прогресс, чтобы можно было продолжить с места остановки.
Когда подходит
- Импорт клиентских данных, загрузка товарных каталогов и массовые миграции пользователей
- Регулярные CSV-выгрузки из внешних систем, которые нужно обрабатывать ночью или по триггеру
На что обратить внимание
- Даже со стриминговым парсером HTTP-обработчик должен оставаться открытым, пока строки записываются. Замедление базы посреди импорта приводит к таймауту на шлюзе, клиент ретраит — и вы получаете дубли строк, если идемпотентность не была заложена с самого начала.
- Управление памятью сложнее, чем кажется: «стриминговый» парсинг CSV, который копит проверенные строки в памяти для массовой вставки, всё равно загружает весь файл в RAM до записи.
Нагрузка и где ломается
Почему обработка CSV ломает синхронные HTTP-обработчики
- Файлы на 100 000+ строк парсятся и вставляются 30–300 секунд — далеко за пределами таймаутов шлюза
- Обработка внутри запроса держит HTTP-соединение открытым — клиенты отваливаются по таймауту или ретраят, создавая двойные импорты
- Давление на память: загрузка CSV на 50 МБ в serverless-функцию одним проходом приводит к OOM на маленьких рантаймах
Импорт CSV — один из самых частых паттернов, которые не помещаются в синхронные HTTP-обработчики. Размер файла непредсказуем, время парсинга и валидации растёт линейно с числом строк, а любой сбой посреди импорта без идемпотентности оставляет частичные данные, из которых трудно восстановиться.
Когда простых рецептов недостаточно
Почему стриминг CSV в HTTP-обработчике хрупок
Даже со стриминговым парсером HTTP-обработчик должен оставаться открытым, пока строки записываются. Замедление базы посреди импорта приводит к таймауту на шлюзе, клиент ретраит — и вы получаете дубли строк, если идемпотентность не была заложена с самого начала.
Управление памятью сложнее, чем кажется: «стриминговый» парсинг CSV, который копит проверенные строки в памяти для массовой вставки, всё равно загружает весь файл в RAM до записи.
Как помогает Inquir
HTTP принимает, пайплайн обрабатывает по частям
HTTP-обработчик проверяет ссылку на файл (URL или ключ в хранилище), сохраняет метаданные задачи и возвращает 202 с ID задачи. Шаг пайплайна читает CSV по частям, делает идемпотентный upsert по ID строки и записывает прогресс, чтобы можно было продолжить с места остановки.
Длинные CSV можно обрабатывать несколькими шагами пайплайна — разбить по диапазонам строк, разветвить параллельно, собрать в итоговом шаге. У каждого шага свой бюджет таймаута; сбой в одном шаге ретраит только его, без перезапуска с первой строки.
Что вы получаете
Паттерны serverless-обработки CSV
Обработка по частям с продолжением
Разбивайте большие CSV на шаги пайплайна по диапазонам строк. Сбой на строке 80 000 продолжается с этой контрольной точки, а не с первой строки.
Параллельный батчевый upsert
Разветвляйте несколько шагов пайплайна, чтобы обрабатывать диапазоны строк параллельно, — общее время импорта больших файлов сокращается.
Идемпотентный upsert строк
Используйте стабильный идентификатор строки (внешний ID или хэш строки) как ключ upsert. Повторный импорт того же файла даёт то же состояние базы.
Отслеживание прогресса и уведомление
HTTP-обработчик возвращает ID задачи. Клиент опрашивает эндпоинт статуса; финальный шаг пайплайна уведомляет вебхуком или письмом по завершении.
Что дальше
Поток serverless-импорта CSV
HTTP-обработчик принимает ссылку на файл, возвращает 202
Проверьте URL файла или ключ в хранилище. Сохраните запись задачи со status=pending. Запустите пайплайн со ссылкой на файл и ID задачи.
Шаг пайплайна читает и обрабатывает CSV
Скачайте и распарсите CSV в шаге пайплайна. Делайте upsert строк батчами по 500–1000 с ключами идемпотентности. Обновляйте прогресс в записи задачи.
Финальный шаг уведомляет
После последнего батча отметьте задачу завершённой и уведомите пользователя письмом, вебхуком или обновлением статуса.
Пример кода
Пайплайн импорта CSV по частям
HTTP-обработчик сразу возвращает 202 и запускает обработчик CSV как durable-инстанс через global.durable.startNew — обычную функцию, которая переживает рестарты и адресуется по id. instanceId делает старт идемпотентным; для очень больших файлов разветвите работу на несколько инстансов по диапазонам строк.
export async function handler(event) { const { fileUrl, importId } = JSON.parse(event.body || '{}'); if (!fileUrl || !importId) return { statusCode: 400, body: JSON.stringify({ error: 'fileUrl and importId required' }) }; await db.imports.create({ id: importId, status: 'pending', fileUrl }); await global.durable.startNew('process-csv', undefined, { fileUrl, importId }); return { statusCode: 202, body: JSON.stringify({ importId, status: 'pending' }) }; }
import { parse } from 'csv-parse/sync'; export async function handler(event) { const { fileUrl, importId } = event; // the input passed to startNew() const csvText = await fetch(fileUrl).then((r) => r.text()); const rows = parse(csvText, { columns: true, skip_empty_lines: true }); let inserted = 0; for (const batch of chunk(rows, 500)) { // Upsert by external_id — idempotent on retry await db.records.upsertBatch(batch.map((r) => ({ ...r, importId }))); inserted += batch.length; } await db.imports.update(importId, { status: 'done', rowCount: rows.length }); return { importId, rows: rows.length, inserted }; }
Когда подходит
Используйте serverless-обработку CSV для
Когда это уместно
- Импорт клиентских данных, загрузка товарных каталогов и массовые миграции пользователей
- Регулярные CSV-выгрузки из внешних систем, которые нужно обрабатывать ночью или по триггеру
Когда лучше выбрать другое
- Крошечные CSV до 1000 строк, которые обрабатываются быстрее 5 секунд, — оставьте их синхронными, отлаживать проще
Частые вопросы
Частые вопросы
Как обрабатывать ошибки валидации CSV?
Собирайте ошибки валидации по строкам и сохраняйте их в записи задачи импорта. По завершении возвращайте сводку (валидные строки, невалидные строки, список ошибок). Пусть клиент решает — принять частичный импорт или сначала исправить ошибки.
Как продолжить упавший импорт?
Храните смещение последней успешно обработанной строки в записи задачи. Перезапустите пайплайн с этим смещением — шаг пропустит уже обработанные строки. Для надёжности делайте upsert по внешнему ID.