EspoCRM: полгода тишины, потом отваливаются письма и триггеры
Первые пару месяцев после установки EspoCRM на собственный сервер всё работает как в рекламном ролике: письма уходят, workflow-правила срабатывают, менеджеры довольны. А потом — без единого обновления, без чьих-либо действий — что-то одно перестаёт работать. Чаще всего это письма: они «отправлены» по статусу в интерфейсе, но получатель их не видит. Или триггер, который полгода исправно переводил сделку в следующий статус, вдруг замолкает, и никто не замечает этого неделями. Проблема в том, что это не баги EspoCRM в привычном смысле — это накопительный эффект работы системы во времени, который никак не проявляется в первый месяц и почти всегда проявляется к пятому-шестому.
Содержание
- Почему проблемы EspoCRM не видны сразу
- Очередь исходящей почты: где она тонет
- Что регулярно проверять по очереди почты
- Workflow и BPM-триггеры: почему они замолкают после обновлений
- Как диагностировать замолкший триггер
- Разрастание базы логов и служебных таблиц
- Регламент: что проверять каждые несколько месяцев
Почему проблемы EspoCRM не видны сразу
EspoCRM спроектирована так, что критичные для долгосрочной эксплуатации процессы — отправка почты, обработка workflow, очистка служебных таблиц — выполняются не по запросу пользователя, а фоново, через cron. Это разумная архитектура: пользователь нажал «отправить письмо» или «сохранить сделку», интерфейс тут же откликнулся, а тяжёлая работа (реальная отправка через SMTP, пересчёт условий workflow, запись в лог действий) уехала в очередь и выполнится следующим тиком cron.
Пока очередь короткая и cron успевает её разгребать, разница между «сохранено» и «выполнено» незаметна: письмо реально уходит через несколько секунд, триггер реально срабатывает почти сразу. Проблема начинает проявляться, когда:
- очередь на отправку растёт быстрее, чем cron успевает её обрабатывать (в EspoCRM — таблица
email_queue_item); - лог действий и системные логи растут без ротации и постепенно замедляют запросы к базе;
- одно из обновлений меняет формат условий workflow, а пересчитанные вручную правила остаются в старом формате;
- SMTP-провайдер вводит суточный лимit или временный бан за объём, о котором никто не думал в момент настройки.
По отдельности каждая из этих вещей выглядит как мелочь. Вместе, спустя 5-6 месяцев непрерывной работы, они складываются в состояние, когда админ открывает CRM и обнаруживает: письма из очереди третий день не уходят, а один из ключевых workflow (например, «через 3 дня без ответа — напомнить менеджеру») не сработал ни разу за последние две недели.
Очередь исходящей почты: где она тонет
В EspoCRM исходящая почта — уведомления, письма из workflow-действий, ручная отправка из карточки лида — сначала попадает в очередь, а реальную отправку через SMTP выполняет cron-задача Email::sendQueue (или общий системный демон cron, если вы не выделили отдельный процесс под очередь). Проверить состояние очереди можно прямо в базе:
SELECT status, COUNT(*) FROM email_queue_item GROUP BY status;
Если в статусе Pending скопились сотни записей, а Sent почти не растёт — очередь не разгребается. Дальше стоит смотреть, в чём причина, по порядку:
1. Cron не запускается вовсе или запускается реже, чем нужно. Проверьте, что задача реально стоит в crontab пользователя, от которого работает веб-сервер (обычно www-data):
crontab -u www-data -l | grep cron.php
Штатная строка выглядит примерно так:
* * * * * /usr/bin/php -f /var/www/espocrm/cron.php > /dev/null 2>&1
Если строки нет — cron физически не выполняется, а очередь копится с момента, когда задача пропала (после переноса сервера, смены пользователя, обновления системы). Как молча пропадает cron-задача и почему это не сразу замечают, разбирали в статье про тихий сбой cron — механизм там общий, не только для CRM.
2. Cron выполняется, но упирается в лимиты SMTP-провайдера. Через полгода активной работы объём исходящей почты обычно вырастает: добавились новые менеджеры, включили больше workflow-уведомлений, начали слать массовые рассылки прямо из CRM. Провайдер, у которого изначально стоял лимит в несколько сотен писем в сутки (типично для бесплатных или базовых тарифов внешних SMTP), начинает отклонять письма или временно блокировать аккаунт при превышении. В логе PHP (обычно data/logs/espo.log) это видно как повторяющиеся ошибки SMTP Error или Connection could not be established — если этих строк много и они привязаны к определённому времени суток (пиковая нагрузка), дело в лимите, а не в самом cron.
3. Одно «зависшее» письмо блокирует очередь. Если один элемент очереди раз за разом падает с ошибкой (битый адрес, вложение, которое SMTP-сервер отклоняет по размеру), а обработчик очереди не помечает его как Failed и не идёт дальше, вся очередь за ним встаёт. Проверить конкретные зависшие записи:
SELECT id, subject, status, created_at FROM email_queue_item
WHERE status = 'Pending' ORDER BY created_at ASC LIMIT 20;
Самые старые записи в этом списке — кандидаты на ручной разбор: посмотреть тело письма, адрес получателя, и либо поправить, либо перевести в Failed, чтобы освободить очередь.
4. Учётная запись исходящей почты отозвана или истёк пароль приложения. Если для отправки используется внешний ящик (Gmail, Yandex, корпоративная почта с двухфакторной аутентификацией), пароль приложения может быть отозван вручную администратором почты, ротацией политики безопасности или истечением срока действия токена OAuth — и это никак не связано с самой EspoCRM, но выглядит как её поломка.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверЧто регулярно проверять по очереди почты
Регламент, который снимает большую часть внезапности:
- раз в неделю — быстрый SQL-запрос на количество
Pending-писем старше суток; если больше нуля, разбираться сразу, не откладывая; - раз в месяц — смотреть реальный объём отправленной почты за месяц и сравнивать с лимитом SMTP-провайдера, если он есть;
- при добавлении нового источника уведомлений (новый workflow, новая интеграция) — заранее прикидывать, насколько вырастет объём писем.
Если своя SMTP-инфраструктура настроена отдельно от CRM, полезно свериться с тем, как в принципе диагностируется недоставленная почта на уровне сервера — например, в статье про DMARC на reject, который отрезал письма от CRM: похожая картина «статус отправлено, получатель молчит» бывает и на уровне SMTP-аутентификации, а не только внутри очереди CRM.
Workflow и BPM-триггеры: почему они замолкают после обновлений
Второй классический сюрприз через несколько месяцев — тихо переставший срабатывать workflow. В EspoCRM автоматизация реализована двумя механизмами: более простой Workflow (условие → действие) и более гибкий BPM (визуальные процессы с ветвлениями). Оба хранят условия не как код, а как структуры в базе (таблицы workflow, bpmn_*), которые интерпретируются движком при каждом сохранении записи.
Здесь копится три типа проблем:
Изменение схемы полей ломает условие тихо. Если поле, на которое ссылается условие триггера (например, кастомное поле «Стадия квалификации»), было переименовано, удалено или пересоздано с другим внутренним именем при доработке CRM — сам триггер в интерфейсе продолжает выглядеть настроенным, но условие фактически ссылается в пустоту и никогда не выполняется. EspoCRM в большинстве версий не показывает явной ошибки в интерфейсе списка workflow — правило просто не срабатывает.
Обновление EspoCRM меняет формат хранения условий. При крупных обновлениях (особенно при переходе между мажорными версиями) внутренний формат условий workflow иногда меняется, и миграция применяется автоматически к правилам, созданным через штатный интерфейс. Но если правило когда-то редактировалось напрямую в базе (например, массовое изменение через SQL при переносе с другого сервера) в обход интерфейса, автоматическая миграция может его не подхватить — и после обновления такое правило перестаёт срабатывать без всякой видимой причины в логах.
Порядок выполнения нескольких триггеров на одно событие. Если на одно и то же событие (например, «Сделка перешла в статус Win») висит несколько правил, а одно из них останавливает дальнейшую обработку (target list changed, entity removed из выборки следующим правилом) — остальные могут просто не доехать до выполнения. Это не поломка в строгом смысле, а следствие того, что правил накопилось больше, чем изначально проектировалось, и никто не пересматривал их взаимодействие.
Как диагностировать замолкший триггер
Порядок действий, который экономит часы:
- Проверить
data/logs/espo.logна записи с ошибками workflow/BPM за период, когда правило должно было сработать. Если ошибок нет вообще — правило, скорее всего, даже не запускалось (условие не совпало), а не упало с исключением. - Пересохранить запись, которая должна была вызвать триггер, вручную через интерфейс — если событие после этого срабатывает, проблема была в конкретном автоматическом действии (например, массовое обновление через API или импорт, которое не генерирует те же хуки, что ручное сохранение).
- Сверить условие правила с реальными значениями поля в базе, особенно если поле — enum/select с фиксированным набором значений:
SELECT DISTINCT stage FROM opportunity;
Если в списке есть значение, которого нет среди вариантов условия триггера (осталось от старой версии справочника, добавлено вручную через админку), записи с этим значением никогда не попадут под условие.
- Проверить, не отключён ли cron-джоб
QueueManager, который выполняет часть отложенных действий workflow (не все действия срабатывают синхронно, часть уходит в очередь заданий аналогично письмам):
SELECT status, COUNT(*) FROM job GROUP BY status;
Скопление записей в статусе Ready при отсутствии продвижения в Success — тот же симптом, что и с очередью почты: cron не успевает или не запускается.
Разрастание базы логов и служебных таблиц
Третья по частоте проблема EspoCRM после полугода — рост нескольких служебных таблиц, которые изначально малы и незаметны, но накапливаются пропорционально активности пользователей:
| Таблица | Что копит | Типичный симптом при разрастании |
|---|---|---|
note | лог действий (комментарии, изменения полей, стрим активности) | тормозит открытие карточек записей с длинной историей |
email_queue_item | все письма, включая уже отправленные, если не чистить | долгий SELECT при диагностике очереди |
job | выполненные и неудавшиеся фоновые задания | замедление cron-тика, если старые записи не удаляются |
action_history_record | история действий пользователей (если включена) | быстрый рост при большой команде |
EspoCRM не всегда чистит эти таблицы автоматически — многое зависит от версии и от того, включена ли соответствующая настройка cleanupJob в панели администратора (Administration → Job). Если её не проверяли с момента установки, велика вероятность, что она работает на значениях по умолчанию, которые не рассчитаны на объём данных полугодовой активной эксплуатации.
Проверить реальный размер таблиц несложно:
SELECT table_name,
ROUND((data_length + index_length) / 1024 / 1024, 1) AS size_mb
FROM information_schema.tables
WHERE table_schema = 'espocrm'
ORDER BY size_mb DESC LIMIT 15;
Если note или job внезапно оказались в топе по размеру рядом с основными таблицами данных (opportunity, contact) — это тревожный признак: индексы на таких таблицах со временем работают всё медленнее, а бэкап базы становится тяжелее и дольше. Про то, как рост логов и служебных данных вообще влияет на сервер за пределами конкретно EspoCRM, есть отдельный разбор про логи, которые никто не читал — механика накопления та же.
Регламент: что проверять каждые несколько месяцев
Практика показывает, что большинство «внезапных» проблем EspoCRM — это события, которые были предсказуемы заранее, просто никто не смотрел на нужные метрики регулярно. Минимальный регламент, который снимает 80% сюрпризов:
- Раз в неделю: количество
Pendingвemail_queue_item; наличие свежих ошибок вespo.log. - Раз в месяц: размер основных служебных таблиц (
note,job,email_queue_item); проверка, что настройки очистки (cleanupJob) в админке действительно включены и запускаются, а не просто отмечены галочкой. - После каждого обновления EspoCRM: ручная проверка 2-3 ключевых workflow/BPM-правил вручную (пересохранить тестовую запись и убедиться, что действие выполнилось) — не полагаться на то, что «раз обновление прошло без ошибок, значит всё работает».
- Раз в квартал: сверка условий workflow-правил со значениями enum-полей, на которые они ссылаются — особенно если справочники (стадии сделки, статусы) редактировались вручную за это время.
Ни один из этих пунктов не требует специального инструмента — все данные лежат либо в логе, либо в базе, доступной через обычный SQL-клиент. Разница между командой, которая раз в квартал тратит 20 минут на такую проверку, и командой, которая узнаёт о проблеме от рассерженного клиента, — это именно наличие регламента, а не технической сложности.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
EspoCRM сама уведомляет, если очередь почты встала?
Нет, штатного алерта на застрявшую очередь в базовой поставке нет. Нужно либо настраивать внешний мониторинг (запрос к БД или к health-эндпоинту, если он у вас есть, по расписанию), либо проверять вручную по регламенту.
Обновление EspoCRM может само сломать работающий workflow?
Напрямую — редко, но косвенно да: если правило редактировалось в обход интерфейса (прямые правки в базе) или ссылается на кастомное поле, изменённое при доработке, автоматическая миграция условий при обновлении может отработать не так, как ожидается. Проверять ключевые правила после каждого крупного обновления — не паранойя, а часть регламента.
Сколько писем в очереди — это уже тревожный сигнал?
Универсального числа нет — зависит от объёма вашей рассылки. Показательнее не абсолютное число, а тренд: если Pending растёт день ото дня и не падает после очередного тика cron, значит очередь не разгребается, и нужно разбираться в причине, а не в конкретной цифре.
Можно ли просто увеличить частоту запуска cron.php, чтобы очередь не копилась?
Это снимает симптом, но не причину. Если очередь растёт из-за реального лимита SMTP-провайдера или из-за одного зависшего письма, которое блокирует остальные, более частый запуск cron только чаще будет упираться в ту же стену. Сначала стоит найти причину роста, а частоту тика — настраивать под реальный объём писем уже после этого.
Нужно ли чистить таблицу note вручную, если cleanupJob не справляется?
Да, если объём накопился уже значительным (десятки гигабайт) — штатная очистка через админку может работать медленно на такой базе. В этом случае разумнее сначала сделать бэкап, затем аккуратно удалить записи старше выбранного срока пакетами (по несколько тысяч строк за раз, чтобы не держать долгую блокировку таблицы), а уже потом включить регулярную автоматическую очистку на будущее.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →