1С и ELMA365 под нагрузкой: как один даунтайм BPM заставил нас переписать интеграцию на Symfony

26.08.26

Интеграция - WEB-интеграция

1С и ELMA365 под нагрузкой: как один даунтайм BPM заставил нас переписать интеграцию на Symfony В понедельник ELMA365 обновлялась 40 минут — а регламентное задание 1С потом три часа висело на таймаутах, держало блокировки и тормозило рабочие места менеджеров. Чужой даунтайм стал нашим. Регламентное задание — не сетевой сервис. Оно не умеет переживать таймауты API, ретраи и очереди сообщений. В статье — с кодом и цифрами из продакшена: • типовой BSL-код синхронного обмена и почему он блокирует 1С; • Symfony-сервис: Messenger, retry с backoff, dead-letter, идемпотентность, webhook с 202; • метрики клиента: задержка 7 мин U94; 3 сек, потерянные сообщения 40/мес U94; 0; • честные контраргументы: почему не написать retry в 1С и сколько стоит инфраструктура; • чек-лист: когда регламентного задания ещё достаточно. Потолок регламентки — ~500–1000 транзакций/час. Дальше разница в архитектуре перестаёт быть теоретической.

Привет, меня зовут Андрей, я руковожу командой, которая делает интеграции 1С с BPM-системами и внешними API. За последние пару лет мы связывали 1С с ELMA365 на нескольких проектах, и каждый раз проходили один и тот же путь: сначала регламентное задание, потом боль, потом вынос интеграции в отдельный сервис.

В этой статье я с кодом и цифрами из продакшена покажу, где у подхода «обработка по расписанию» архитектурный потолок, и как асинхронная шина на Symfony решает проблему надёжности обмена. Сразу оговорка: регламентное задание — нормальный инструмент для своей ниши, и я не собираюсь его хоронить. Речь о том, где эта ниша заканчивается.

 

С чего началось: инцидент на 300 процессов в день

Торговая компания, около 300 запусков BPMN-процессов в сутки. Интеграция была сделана «как у всех»: внешняя обработка, регламентное задание каждые 5 минут, прямые HTTP-вызовы к API ELMA365.

В один понедельник ELMA365 обновлялась и была недоступна 40 минут. Задание всё это время висело на таймаутах, потом начало разгребать накопившийся backlog: три часа оно молотило базу, держало блокировки и тормозило рабочие места менеджеров. Интеграция с внешней системой деградировала скорость основной учётной системы.

Вот этот момент — когда чужой даунтайм становится вашим даунтаймом — и есть граница применимости синхронной схемы.

 

Как обычно выглядит синхронная интеграция

Классика жанра у интеграторов:

Процедура ОбработкаЗадания() Экспорт

    Выборка = ПолучитьЗаказыНаПередачу(); // ~200 документов за проход

    Для Каждого Заказ Из Выборки Цикл

        Запрос = Новый HTTPЗапрос("/api/v1/orders");
        Запрос.Заголовки.Вставить("Authorization", "Bearer " + ПолучитьТокен());
        Запрос.УстановитьТелоИзСтроки(СформироватьJSON(Заказ), "application/json");

        Соединение = Новый HTTPСоединение(
            "elma.company.ru", 443, , , ,
            Новый ЗащищенноеСоединениеOpenSSL(), 30);

        Попытка
            Ответ = Соединение.ОтправитьДляОбработки(Запрос);
            ОтметитьПереданным(Заказ.Ссылка);
        Исключение
            ЗаписатьВЖурналРегистрации(ОписаниеОшибки());
            // документ подхватится в следующий проход...
            // если не сломается логика флагов
        КонецПопытки;

    КонецЦикла;

КонецПроцедуры

Формально это «настоящая» интеграция по API. Но выполняется она внутри того же процесса, что и весь остальной учёт. Что это означает под нагрузкой:

  • Блокирующее ожидание. Пока обработка ждёт ответ API (до 30 секунд на документ при деградации сети), задание заблокировано целиком. 200 документов × таймаут = часы простоя очереди.
  • Retry и очереди пишутся руками. Встроенный язык не даёт из коробки exponential backoff, dead-letter очередей и rate limiter. Это либо самописный код, плохо покрытый тестами, либо его просто нет.
  • Нагрузка на основную базу. Каждый HTTP-вызов выполняется в том же кластере, где работают пользователи. При росте объёма обмена тормозят интерфейсы и отчёты.
  • Слабая наблюдаемость. Логи в журнале регистрации или текстовом файле. Без Prometheus/Grafana о проблеме вы узнаете по жалобе пользователя, а не по алерту.
  • Риск при обновлениях. Обработка встроена в конфигурацию или расширение — обновление типовой 1С может конфликтовать с метаданными, и разбирать это придётся вручную.

По нашему опыту, практический потолок такой схемы — порядка 500–1000 транзакций в час для производственных и торговых предприятий с активными BPM-процессами. Цифра ориентировочная: у вас она может отличаться в зависимости от частоты запусков процессов и сложности контекстов. Но порядок именно такой.

 

Что мы сделали вместо этого: отдельный сервис на Symfony

Идея простая: интеграция — это не часть учёта, это отдельный сетевой сервис, который должен переживать таймауты, ретраи и очереди сообщений. Архитектура получилась такая:

 

 

  • 1С публикует события (новый заказ, смена статуса) — быстрым POST на эндпоинт коннектора или через таблицу регистрации изменений с курсором;
  • коннектор (Symfony) мгновенно кладёт событие в очередь (Messenger) и возвращает 202 — 1С не ждёт, пока ELMA365 соизволит ответить;
  • consumer-воркеры разбирают очередь и общаются с API ELMA365 со всеми ретраями;
  • webhook'и от ELMA365 (статусы согласований) принимаются тем же коннектором и так же уходят в очередь, а затем пишутся обратно в 1С через HTTP-сервис.

Ключевой момент: 1С кладёт событие в очередь за миллисекунды. Недоступность ELMA365 больше не блокирует ничего внутри 1С — сообщения просто ждут своей очереди.

 

Конфигурация Messenger: retry и dead-letter из коробки

# config/packages/messenger.yaml
framework:
  messenger:
    failure_transport: failed

    transports:
      elma_sync:
        dsn: '%env(MESSENGER_TRANSPORT_DSN)%'   # doctrine://default?queue_name=elma_sync
        retry_strategy:
          max_retries: 5
          delay: 1000        # 1 сек
          multiplier: 2      # 1 -> 2 -> 4 -> 8 -> 16 сек
          max_delay: 60000
      failed:
        dsn: 'doctrine://default?queue_name=failed'

    routing:
      App\Message\SyncOrderToElmaMessage: elma_sync

Это готовые паттерны фреймворка, а не самописный код внутри обработки: они предсказуемо работают и покрыты тестами Symfony.

 

Сообщение и обработчик с идемпотентностью

// src/Message/SyncOrderToElmaMessage.php
final readonly class SyncOrderToElmaMessage
{
    public function __construct(
        public string $orderRef,  // GUID ссылки 1С
        public int $revision,     // версия данных для идемпотентности
    ) {}
}
// src/MessageHandler/SyncOrderToElmaHandler.php
#[AsMessageHandler]
final readonly class SyncOrderToElmaHandler
{
    public function __construct(
        private OneCOrderReader $oneC,
        private Elma365Client $elma,
    ) {}

    public function __invoke(SyncOrderToElmaMessage $message): void
    {
        $order = $this->oneC->readOrder($message->orderRef);

        if ($order === null) {
            return; // документ удалён в 1С — просто забываем
        }

        if ($order->revision <= $this->elma->lastSyncedRevision($message->orderRef)) {
            return; // идемпотентность: эта версия уже отправлена
        }

        $this->elma->upsertOrder($order);
    }
}

Идемпотентность через revision — обязательна. При ретраях и дублях событий (а они будут) вы не должны дважды завести один и тот же заказ в BPM.

 

Webhook от ELMA365: принимаем за миллисекунды

// src/Controller/ElmaWebhookController.php
#[Route('/webhook/elma365/process-status', methods: ['POST'])]
public function processStatus(Request $request, MessageBusInterface $bus): Response
{
    // Синхронно только проверяем подпись — обработку в фон
    $payload = $this->signatureVerifier->verify($request);

    $bus->dispatch(new ApplyProcessStatusMessage(
        processId: $payload['processId'],
        status: $payload['status'],
    ));

    return new Response('', Response::HTTP_ACCEPTED); // 202 за миллисекунды
}

Webhook принимается мгновенно и обрабатывается в фоне — без риска таймаута на стороне ELMA365 и без потери статусов при перезапусках.

 

Масштабирование и наблюдаемость

# docker-compose.yml
services:
  worker:
    build: .
    command: php bin/console messenger:consume elma_sync --time-limit=3600
    restart: always
    depends_on: [ db ]
  db:
    image: postgres:16
docker compose up -d --scale worker=3

Рост транзакций до десятков тысяч в сутки — это увеличение числа воркеров одной командой, а не переписывание логики. Плюс отдельный сервис тривиально подключается к Prometheus/Grafana: метрики очереди, алерты при росте dead-letter — то, что внутри 1С организуется с большим трудом.

 

Реальные цифры из продакшена

Для иллюстрации — метрики одного из наших клиентов (производство металлоконструкций, ~180 сотрудников, 1С:ERP 2.5 + ELMA365). Интеграцию мигрировали с регламентного задания на Symfony-сервис без изменения бизнес-логики:                                                                                                                                                      

Показатель Было (рег. задание 1С) Стало (Symfony)
Транзакций в сутки ~4 000 ~4 000
Средняя задержка 1С→ELMA 7 минут 3 секунды
Потерянных сообщений за месяц ~40 0
«Зависших» процессов 12 в месяц 0
Жалоб пользователей на «тормоза» ~15 в месяц 0
Восстановление после падения API ELMA Ручной перезапуск Автоматически, за 2–4 минуты

 

Самая дорогая строка здесь — последняя. При регламентном задании каждый даунтайм ELMA365 превращался в ручную работу: кто-то должен заметить сбой, перезапустить задание, вручную проверить, что дошло. Теперь очередь просто переживает даунтайм и разбирает backlog за минуты без участия человека.

 

Прямое сравнение                                                                                     

                                              

Критерий Регламентное задание 1С Symfony-коннектор
Задержка передачи данных Минуты (интервал задания) Секунды (событийная модель)
Retry при сбое API Только если написано вручную Из коробки (Messenger)
Dead-letter очередь Нет (нужно писать регистр) Встроено
Нужна отдельная инфраструктура Нет Да (сервис + очередь)
Нагрузка на базу 1С Есть, растёт с объёмом Нет (вынесена наружу)
Кто дорабатывает 1С-программист PHP/Symfony-разработчик
Практический потолок по транзакциям До ~500–1000/час Практически не ограничен

 

Честные контраргументы

«Retry можно написать и в 1С». Можно. Но тогда вы пишете свой Messenger на встроенном языке: без нормальных тестов, без dead-letter, без метрик. Это изобретение велосипеда с квадратными колёсами, который ещё и поддерживать вашему же коллеге.

«Почему Symfony, а не .NET или Node?». Не принципиально. Суть — паттерны: очередь, воркеры, идемпотентность, раздельное деплой. Symfony — наш стек, но те же принципы перекладываются на любой язык.

«Это лишняя инфраструктура». Да, и это честная цена гибкости: нужен сервер или контейнер под сервис и очередь. Минимально — 2 vCPU / 4 GB под сервис и столько же под брокер; на практике для нагрузки до 10 000 транзакций в сутки хватает одной VM 4 vCPU / 8 GB с Docker Compose. Для небольшого офиса с полусотней процессов в день это избыточно. Для растущего предприятия — дешевле, чем простой согласований.

«А как же обновления 1С?». В этом и плюс: коннектор живёт вне конфигурации, общается с 1С через OData или HTTP-сервисы, и обновление типовой конфигурации его не затрагивает.
 

Чек-лист: когда регламентного задания достаточно

Задайте себе три вопроса:

Сколько у вас транзакций в час и насколько критична задержка? До пары сотен операций и допустимая задержка в 5–10 минут — регламентного задания достаточно. Тысячи операций с требованием near real-time — нужна событийная модель.

Сколько стоит вам один «зависший» бизнес-процесс? Если остановки согласований или потери контекста уже влияют на операционную деятельность — это сигнал, что архитектурный потолок текущего решения достигнут.

Кто будет поддерживать интеграцию дальше? Если в штате есть только 1С-разработчик — миграция на отдельный сервис означает либо обучение, либо привлечение подрядчика на сопровождение.

И отдельно — сценарии, где городить отдельный сервис действительно нет смысла:

  • Фоновая синхронизация справочников раз в час;
  • Ночная выгрузка отчётности;
  • До пары сотен операций в час с допустимой задержкой в 5–10 минут.
     

Вопросы к сообществу
 

  • Как вы реализуете retry в своих регламентных заданиях? Есть ли у вас самописные механизмы dead-letter, или ограничиваетесь «Попытка...Исключение»?
  • Используете ли вы SQL-реплику 1С для интеграций? Какие подводные камни встречали с прямым чтением таблиц AccumRg* и InfoRg*?
  • Какой брокер сообщений предпочитаете в 1С-интеграциях — RabbitMQ, Kafka или что-то другое? Почему?
  • Сталкивались ли с ситуацией, когда регламентное задание «падало» из-за таймаута внешнего API и блокировало пользовательские сеансы? Как решали?


Итог

Регламентное задание прекрасно знает, как устроен ваш учёт. Но оно никогда не проектировалось как сетевой сервис, который должен переживать таймауты API, ретраи и очереди сообщений, — а именно это нужно для стабильной работы BPM-процессов при высокой нагрузке.

Если счёт идёт на тысячи транзакций в час, а остановки согласований уже стоят денег — разница в архитектуре перестаёт быть теоретической. Поэтому интеграции 1С ↔ ELMA365 мы теперь делаем не как обработку внутри 1С, а как отдельный сервис — с расчётом, что он будет расти вместе с бизнесом, а не упрётся в потолок через год.

Об авторе: Андрей Болонин, ModernERP. Проектируем интеграционные шины 1С ↔ BPM (ELMA365) и внешние API для среднего бизнеса. Буду рад ответить в комментариях на вопросы по архитектуре под ваши нагрузки — на Infostart комментарии часто полезнее самой статьи.

Вступайте в нашу телеграмм-группу Инфостарт

1С:Предприятие 1С:ERP Интеграция ELMA365 Symfony PHP RabbitMQ Архитектура Highload Регламентные задания OData BPM

Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

См. также

WEB-интеграция Анализ продаж Системный администратор Программист Пользователь 1С:Предприятие 8 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Управленческий учет Платные (руб)

Модуль "Подсистема интеграции AmoCRM с 1С" позволяет обеспечить единое информационное пространство, в котором пользователи могут эффективно управлять клиентской базой, следить за статусами сделок и поддерживать актуальность данных как в AmoCRM, так и в 1С.

60000 руб.

07.05.2019    43983    76    45    

32

Сайты и интернет-магазины WEB-интеграция Системный администратор Программист Пользователь 1С:Предприятие 8 1C:Бухгалтерия 1С:Управление торговлей 11 Автомобили, автосервисы Россия Управленческий учет Платные (руб)

Интеграционный модуль обмена между конфигурацией Альфа Авто 5 и Альфа Авто 6 и порталом AUTOCRM / LOGICSTARS. Данный модуль универсален. Позволяет работать с несколькими обменами AUTOCRM / LOGICSTAR разных брендов в одной информационной базе в ручном и автоматическом режиме.

42700 руб.

03.08.2020    25093    39    26    

29

WEB-интеграция Системный администратор Программист Пользователь 1С:Предприятие 8 1C:Бухгалтерия 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 Автомобили, автосервисы Россия Управленческий учет Платные (руб)

Интеграционный модуль обмена по API между конфигурацией 1С:Альфа-Авто 6 и порталом LogicStar. Позволяет работать с несколькими обменами LogicStars разных брендов (CHERY, OMODA, JAECOO, EXEED, TENET) в одной информационной базе в ручном и автоматическом режиме. Поддерживается выгрузка заказ-нарядов, реализаций товаров и товарных остатков.

20740 руб.

13.05.2025    2597    4    0    

7

WEB-интеграция Программист 1С:Предприятие 8 1С:Бухгалтерия 3.0 Бытовые услуги, сервис Платные (руб)

Расширение для автоматизации передачи данных между сервисом Vetmanager с 1С: Бухгалтерия 3.0. Решение позволяет загружать документы и справочники из Ветменеджер в 1С:Бухгалтерию, сокращая время на ручной ввод данных и минимизируя ошибки.

24000 руб.

02.02.2021    23772    72    52    

44

WEB-интеграция Программист Бизнес-аналитик 1С:Предприятие 8 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Оптовая торговля, дистрибуция, логистика ИТ-компания Платные (руб)

Модуль "Экспортер" — это расширение для 1С, предназначенное для автоматизации процессов выгрузки данных. Оно позволяет эффективно извлекать, преобразовывать и передавать данные из систем 1С в интеграционную платформу Spot2D. Подсистема упрощает настройку, снижает количество ручных операций и обеспечивает удобный контроль данных.

17568 руб.

20.12.2024    7058    30    4    

31
Для отправки сообщения требуется регистрация/авторизация