Генерация больших Excel отчетов без таймаутов: опыт внедрения Spring Batch

20 марта 2026

Как организовать пакетную генерацию Excel отчетов на Java, чтобы пользователи могли запускать десятки и сотни документов за раз без зависаний и таймаутов? Разбираем архитектуру решения на Spring Batch, схему обработки, расчет прогресса и интеграцию с фронтендом.

Проблема генерации больших Excel отчетов

В одном из реализованных нами продуктов, предназначенном для автоматизации бизнес-процессов ремонта авиационных двигателей, нам регулярно нужно переводить бизнес сущности в физический формат. Речь идет о рабочих картах с пошаговыми инструкциями и маршрутных листах, которые формируются в Excel или PDF и далее распечатываются на производстве.

На практике пользователи могут запускать печать десятков или сотен документов одновременно. Если обрабатывать большой объем данных синхронно в рамках одного HTTP запроса, система неизбежно упирается в таймауты. Браузер ждет ответ, сервер удерживает соединение, ресурсы блокируются.

На Python бэкенде для подобных задач используется Celery с Redis в роли брокера и оркестратора. Для Java сервиса мы выбрали Spring Batch — фреймворк, предназначенный для пакетной обработки данных с поддержкой чанков, хранения состояния и восстановления после сбоев.

Архитектура Spring Batch: Job, Step, Tasklet

Spring Batch строится вокруг трех ключевых понятий (подробнее в официальной документации или в более коротком туториале на Baeldung):

Job — единица пакетной работы верхнего уровня.В нашем случае это полный цикл: сгенерировать пакет Excel документов, упаковать их в архив и загрузить в файловый сервис.

Step — логически завершенный этап внутри Job.Step может быть:

  • chunk oriented — чтение, обработка и запись порциями 
  • tasklet based — выполнение одной атомарной операции 

Tasklet — интерфейс для шага, который выполняет одно действие и завершает работу.

Такое разделение позволяет разбить процесс генерации Excel отчетов на независимые этапы и управлять ими централизованно.

Разбиение процесса генерации Excel на шаги

В нашем случае шаги выглядят так:

Picture   2026 03 20 T153128.448

Шаг 1. PRINT — генерация Excel

На вход Step поступает подготовленный список данных. Конфигурация Spring Batch разбивает его на чанки по 10 элементов.

Каждый чанк проходит через:

  • reader — получает порцию данных 
  • processor — конвертирует их в Excel файл 
  • writer — сохраняет результат на диск 

@Bean

@JobScope

public Step printTrpTagsStep(

        ItemReader<TrpTagForPrintModel> excelTrpTagItemReader,

        ItemProcessor<TrpTagForPrintModel, ExcelItem> excelTrpTagItemProcessor,

        ItemWriter<ExcelItem> excelTrpTagItemWriter

) {

    return new StepBuilder(BatchExcelPrintStep.PRINT.getCode(), jobRepository)

 

    .<TrpTagForPrintModel, ExcelItem>chunk(10)

            .transactionManager(transactionManager)

            .reader(excelTrpTagItemReader)

            .processor(excelTrpTagItemProcessor)

            .writer(excelTrpTagItemWriter)

            .build();

}

Spring Batch автоматически ведет счетчик writeCount. Это позволяет отслеживать прогресс генерации и не держать все файлы в памяти одновременно.

Структура временных файлов после завершения шага PRINT:

/tmp/engine/{timestamp}/

├── models.json

└── zip/

    ├── kitting-list-1/

    │   ├── Off_Tag_FERRULE.xlsx

    │   └── Off_Tag_FERRULE (1).xlsx

    └── kitting-list-2/

        └── Off_Tag_BLADE.xlsx

Шаг 2. ZIP — архивирование

После завершения генерации отдельный Tasklet проходит по директории и упаковывает все файлы в единый ZIP архив стандартными средствами Java.

Шаг 3. UPLOAD — загрузка в S3

Готовый архив загружается в S3. Ссылка на файл сохраняется в ExecutionContext.

Шаг 4. CLEAN_UP — очистка временных файлов

После успешной загрузки временные файлы удаляются из каталога /tmp пода.

Если Job завершится с ошибкой до этапа очистки, используется JobExecutionListener. В нем проверяется статус выполнения, и при необходимости запускается логика удаления временных данных.

Параллельная генерация Excel документов

Spring Batch поддерживает параллельное выполнение шагов. В нашем случае этого не потребовалось. Для масштабирования мы используем Thread Pool и запускаем несколько Job параллельно.

Это позволяет обрабатывать несколько запросов пользователей одновременно без усложнения внутренней логики одного Job.

Отображение прогресса генерации на фронтенде

Асинхронная генерация Excel отчётов требует прозрачного механизма отслеживания статуса.

API для отслеживания статуса

После запуска Job клиент получает jobExecutionId. Фронтенд периодически опрашивает endpoint статуса и получает актуальные данные о выполнении.

POST /trp-tag/print/excel/batch/start → { jobExecutionId: 12345 }

GET  /trp-tag/print/excel/batch/12345 → { status, progressPercentage, downloadUrl, ... }

Расчет прогресса

Шаги имеют разную продолжительность. Генерация Excel занимает около 90 процентов времени, архивирование, загрузка и очистка — оставшиеся 10 процентов.

Для шага PRINT прогресс рассчитывается пропорционально через writeCount — встроенный счетчик Spring Batch, который увеличивается после каждого чанка.

Для остальных шагов используется бинарная логика: либо этап не выполнен, либо выполнен полностью.

Фронтенд получает все необходимое, чтобы пользователь видел понятный прогресс:

  • progressPercentage — значение для прогресс-бара 
  • currentStepNumber и totalStepsNumber — текстовый индикатор шага 
  • status — STARTED, COMPLETED или FAILED 
  • downloadUrl — ссылку на скачивание архива 
  • failureDetails — описание ошибки при сбое 
  • durationMillis — общее время выполнения 

Что дало внедрение Spring Batch

Асинхронность.

Пользователь мгновенно получает идентификатор задачи, а не ждет завершения генерации. Это принципиально изменило UX: вместо зависшего экрана — прогресс-бар с процентом выполнения.

Прозрачность и контроль.

Spring Batch автоматически сохраняет данные о Job и Step Execution в PostgreSQL. Мы получили историю запусков, длительность выполнения, счетчики обработанных элементов и информацию об ошибках без дополнительной инфраструктуры.

Управление состоянием.

Фреймворк берет на себя транзакционность, персистентность состояния и корректное завершение шагов. При использовании простых асинхронных методов такую логику пришлось бы реализовывать вручную при использовании простых @Async-методов. 

Итог

Spring Batch оказался оптимальным решением для пакетной генерации больших Excel отчетов в Java сервисе. Он позволяет обрабатывать сотни документов без таймаутов, контролировать прогресс в реальном времени и сохранять устойчивость системы при сбоях.

Если перед вами стоит задача массовой генерации документов, архивирования и загрузки в файловое хранилище, архитектура на базе Spring Batch дает управляемость, масштабируемость и прозрачность на уровне продакшена.

Недавние публикации