История выполнений в n8n похожа на бортовой журнал: пока корабль идёт ровно, в него почти никто не заглядывает, а в день, когда что-то пошло не так, именно он решает, будет ли разбор спокойным или превратится в гадание. Но у журнала есть неприятное свойство: он пишется каждый рейс. Если сценарии запускаются часто, а срок хранения никто не выбирал, журнал растёт сам по себе и однажды занимает место, которое нужно самой PostgreSQL для работы. Сценарии при этом могут быть абсолютно здоровыми. Остановит их не ошибка в логике, а то, что писать больше некуда.
Поэтому разговор о чистке стоит начинать не с команды удаления, а с вопроса: что именно из этих записей вам когда-нибудь понадобится, и сколько места они займут при выбранном сроке. Ответ на оба вопроса можно получить арифметикой и парой запросов к собственной базе.
Что полезного в успешном запуске, а что в упавшем
Выполнения неравноценны. Успешный запуск, который каждые пять минут проверяет, нет ли новых заявок, и в девяти случаях из десяти ничего не находит, почти не несёт информации. Достаточно знать, что он отработал. Копия его входных и выходных данных за прошлый вторник вам не пригодится никогда.
Упавший запуск устроен иначе. В нём есть узел, на котором всё оборвалось, входные данные этого узла, текст ошибки и время. Это материал для расследования: по нему видно, какой именно элемент данных сломал сценарий, а не только то, что сценарий сломался. Если такую запись удалить через два дня, а о проблеме вы узнаете через неделю, воспроизводить придётся по памяти.
Отсюда первая практическая развилка. В документации n8n об execution data описано, что можно выбирать, какие выполнения сохранять, и очищать старые завершённые записи. Это даёт два независимых рычага: что вообще писать в историю и как долго хранить уже записанное. Их разумно настраивать по-разному для разных типов сценариев:
- частые «сторожевые» сценарии, которые почти всегда завершаются успешно: сохранять успешные запуски нет смысла, достаточно ошибок;
- сценарии с деньгами, заказами, письмами клиентам: успешные запуски полезны как след того, что именно было отправлено, поэтому срок для них длиннее;
- редкие тяжёлые сценарии с большими данными на входе: каждая запись весит много, и именно здесь экономия заметнее всего.
Настройки на уровне конкретного сценария и глобальные переменные окружения имеют свои названия и приоритеты, их лучше сверять по документации для вашей версии, а не переписывать по памяти. Здесь важна сама логика: политика хранения должна следовать за ценностью записи, а не быть одной цифрой на всё.
Как посчитать, когда закончится диск
Оценка роста нужна не для красоты. Она отвечает на практический вопрос: сколько у вас времени и какой срок хранения вы можете себе позволить. Модель состоит из трёх множителей: сколько выполнений в сутки, сколько в среднем занимает одна запись и сколько суток вы их держите.
Возьмём условный пример, цифры вымышленные и нужны только для демонстрации хода рассуждения. Допустим, есть сценарий, который запускается каждые 5 минут: это 288 запусков в сутки. Ещё несколько сценариев по событиям дают в сумме около 700 запусков. Итого примерно 1000 выполнений в сутки. Пусть средняя запись, вместе с данными узлов, занимает 40 КБ. Тогда за сутки добавляется около 40 МБ, за неделю около 280 МБ.
Теперь два сценария политики:
| Срок хранения | Записей в базе на плато | Объём на плато |
|---|---|---|
| 7 суток | около 7 000 | около 280 МБ |
| 30 суток | около 30 000 | около 1,2 ГБ |
| Без очистки, 365 суток | около 365 000 | около 14,6 ГБ и дальше растёт |
Главная мысль таблицы в слове «плато». Пока очистка включена, объём истории не растёт бесконечно: он выходит на уровень «суточный прирост, умноженный на срок хранения», и дальше колеблется около него. Недельный прирост 280 МБ при семидневном сроке означает, что через неделю старые записи начнут уходить с той же скоростью, с какой приходят новые. Без очистки линия просто продолжается вверх, и вопрос только в том, на какой день она упрётся в размер диска.
Разберём плато на тех же цифрах, по неделям. Пусть политика хранения 7 суток, а прирост равен 40 МБ в сутки. К концу первой недели история занимает около 280 МБ, и удалять пока нечего: все записи моложе срока. На восьмой день в базу приходят новые 40 МБ, а очистка убирает записи первого дня, тоже около 40 МБ. Объём, который занимают живые строки, остаётся около 280 МБ. Если срок поднять до 30 суток, ту же точку вы пройдёте не через неделю, а через месяц, и это самая коварная часть: первые четыре недели график выглядит как обычный рост, а плато в 1,2 ГБ показывает себя только после выхода на срок. Поэтому по первым дням нельзя судить, хорош ли выбранный срок. Сравнивайте не текущий размер, а произведение суточного прироста на срок.
Есть и простая проверка модели на чувствительность. Если средняя запись вырастет с 40 до 100 КБ, например из-за нового сценария с крупным JSON, плато при 7 сутках станет 700 МБ вместо 280, а при 30 сутках около 3 ГБ вместо 1,2. Одно изменение в одном сценарии сдвигает всю картину в 2,5 раза, поэтому пересчитывайте оценку каждый раз, когда добавляется сценарий с большими данными или частым расписанием.
Обратите внимание, как сильно на результат влияет размер записи. Если один из сценариев получает на вход крупный JSON на несколько мегабайт, он может весить больше, чем все остальные вместе. Поэтому среднее по больнице считать опасно: посмотрите распределение. Узнать, какие сценарии дают основной объём, можно, сгруппировав выполнения по идентификатору сценария и посчитав их число, а размер данных сопоставить с самими записями. Точные имена таблиц и столбцов зависят от версии n8n, поэтому перед запросами к служебной схеме сверьтесь со своей установкой и делайте только чтение. Вручную удалять строки из рабочих таблиц n8n не нужно: для этого есть штатная очистка, а ручное вмешательство легко оставит несогласованные связи.
Для оценки самого факта роста есть и более простой путь, не зависящий от схемы. Раз в сутки записывайте размер базы стандартной функцией PostgreSQL pg_database_size и размер свободного места на диске. Две точки с разницей в сутки дают реальный прирост, который можно сравнить с расчётом. Если расчётные 40 МБ превращаются в измеренные 120, значит, вы недооценили размер записи или забыли о других потребителях места.
SELECT pg_size_pretty(pg_database_size(current_database()));Записи, которые pruning не тронет
Дальше начинаются тонкости, из-за которых аккуратно рассчитанное плато вдруг не наступает. По документации, выполнения в статусах running, new и waiting не подпадают под обычную очистку: удаляются старые завершённые записи. Логика понятна: нельзя стирать то, что ещё может продолжиться.
Но на практике это означает, что «зависшие» записи накапливаются без ограничения срока. Выполнение со статусом waiting может ждать внешнего события, и если событие так и не пришло, запись остаётся. Запуск, который был прерван перезапуском сервера, иногда остаётся в статусе running, хотя ничего уже не выполняется. Такие записи редки по сравнению с миллионами успешных, но у них нет срока годности, и среди них бывают тяжёлые, потому что ожидающий сценарий держит данные, с которыми должен продолжить работу.
Практический вывод такой: раз в неделю смотрите, сколько записей находится в этих статусах и как давно самая старая. Если самая старая ожидает три месяца, это не история, а забытый процесс, и решение по нему принимает человек: дождаться, отменить или признать ошибкой в логике сценария. Автоматическая очистка этого решения за вас не примет, и в этом её честное ограничение, а не недоработка.
Разберём на условном примере, как зависшие записи ломают расчёт. Допустим, сценарий согласования ждёт внешнего ответа и держит около 2 МБ данных, чтобы продолжить работу. Если из-за ошибки на стороне партнёра ответ не приходит в одном случае из ста, а запусков в сутки 200, то за сутки появляются две такие записи, то есть около 4 МБ, которые срок хранения не ограничивает. За 30 суток это 120 МБ, за год около 1,4 ГБ, и это без учёта обычной истории. На графике плато при этом будет медленно, но стабильно ползти вверх, и причину легко принять за неточность в оценке размера записи.
Отличить такой рост от обычного можно по составу: если число завершённых записей стабильно, а общий размер продолжает расти, ищите причину среди ожидающих и незавершённых выполнений. Сведения о том, что такие статусы обычной очисткой не затрагиваются, приведены в документации n8n об execution data.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации Россия, США, Франция и Великобритания. Оплата картой РФ и по СБП.
Что растёт вне строк базы
Простая модель «число записей на размер записи» описывает только таблицы. Реальный диск сервера занят не только ими, и вторая половина картины часто оказывается неприятнее первой.
Первое: удаление строк и уменьшение файла базы не одно и то же. После очистки PostgreSQL помечает место внутри файлов как пригодное для повторного использования, и новые записи будут ложиться в освободившиеся области. Это хорошо для плато: рост прекращается. Но размер файлов на диске при этом не обязан сразу падать, а команды, которые физически возвращают место операционной системе, имеют свои условия и блокировки. Поэтому нельзя считать, что после первой очистки вы увидите свободные гигабайты в выводе df. Подтверждайте результат измерением: размер базы до и после, свободное место до и после, и только потом делайте выводы. Если вам нужно вернуть место немедленно, это отдельная плановая операция обслуживания PostgreSQL, которую стоит делать в окно работ и после проверки копии, а не в спешке на живой системе.
Второе: бинарные данные и пользовательская папка. Согласно разделу n8n о резервном копировании и восстановлении, полная копия включает пользовательскую папку и внешнюю базу данных, если вы её используете. Внешнее хранилище и пользовательские узлы тоже нужно копировать отдельно. Значит, часть данных живёт на файловой системе, и размер таблиц её не показывает. Если сценарии обрабатывают файлы, вложения или PDF, проверьте, где они физически оказываются на вашей установке, и добавьте этот каталог в учёт места отдельной строкой.
Третье, и самое ироничное: резервные копии занимают то же место, что и сама база. Если ночной дамп хранится на том же диске и каждые сутки пишется новый файл, то при базе в 1,2 ГБ и хранении десяти копий вы получаете ещё около 12 ГБ. Чем больше история в базе, тем больше каждая копия, и тем быстрее забивается диск. Очистка истории поэтому уменьшает не только саму базу, но и каждый будущий дамп. Хранить копии на этом же диске, к тому же, плохая привычка по другой причине: если диск уйдёт, уйдут и база, и копии. Лучше отправлять их в другое место.
Сложим всё в одну строку учёта, чтобы увидеть полную картину, а не только таблицы. Для условной базы с плато в 1,2 ГБ возьмём десять копий на том же диске, это ещё около 12 ГБ. Добавим пользовательскую папку с вложениями, скажем 3 ГБ, и систему с образами контейнеров и логами, скажем 10 ГБ. Итого около 26 ГБ. На диске в 40 ГБ остаётся запас менее 15 ГБ, и свободное место окажется ближе к границе, чем подсказывает размер самой базы. На диске в 80 ГБ та же нагрузка занимает чуть меньше трети. Цифры вымышленные, но порядок рассуждения важен: основной потребитель места здесь не история выполнений, а копии, и поэтому сокращение срока хранения даёт двойной эффект. Меньше база, и меньше каждый дамп.
Практическое следствие: сравнивайте срок хранения копий с сроком хранения истории. Хранить десять суточных дампов базы, в которой записи живут семь суток, значит держать каждую запись в десяти местах одновременно. Часто достаточно меньшего числа копий на самом сервере и более длинного архива в другом месте.
Есть и обратная сторона. В той же документации сказано, что без ключа шифрования credentials не расшифровать. Копия базы без этого ключа даёт историю и сценарии, но не рабочие учётные данные. Поэтому ключ должен храниться отдельно от самой копии и рядом с ней в инструкции по восстановлению, иначе вы проверите бэкап «на бумаге» и обнаружите проблему только в день аварии.
Как выбрать срок и не потерять нужное
Теперь у нас есть всё для решения. Срок хранения определяется не вкусом, а двумя величинами: сколько времени проходит между сбоем и моментом, когда о нём узнают, и сколько места вы готовы отдать под историю.
Если о сбоях вы узнаёте в течение суток, а разбираетесь максимум за пару дней, то держать успешные записи дольше недели нечем оправдать. Если же отчёты уходят клиентам раз в месяц и претензии приходят в конце периода, для таких сценариев нужен более долгий срок, и тогда лучше сохранять в историю только их, а остальным ограничить срок жёстче. Хорошо работает такая схема из трёх уровней:
- ошибки: хранить дольше всего, они маленькие по числу и самые ценные;
- успешные запуски важных сценариев: средний срок, достаточный для сверки с отчётностью;
- успешные запуски частых служебных сценариев: не сохранять или держать считанные дни.
Когда политика выбрана, пересчитайте плато по таблице выше уже с реальными цифрами и сравните с размером диска. На VPS это удобно делать вместе с выбором ресурсов: для тарифов MAATRIX указаны объёмы NVMe, например 40 ГБ у Ba, 80 ГБ у Uab, 160 ГБ у Heka, и из них нужно вычесть систему, образы контейнеров, логи и копии. Эти цифры показывают размер диска, а не обещание ёмкости под конкретную нагрузку: сколько выполнений поместится, зависит от размера ваших записей. Если расчётное плато вместе с копиями занимает больше половины диска, то лучше либо сократить срок, либо взять тариф с запасом. Запас здесь дешевле, чем аварийная чистка. Если вы разворачиваете n8n на VPS заново, в публичном каталоге есть вариант с установкой n8n; наличие образа и операционную систему стоит проверить в форме заказа. Подробнее о конфигурациях: аренда VPS MAATRIX.
Наблюдение за приростом вместо героической чистки
Самая надёжная защита от переполнения скучна: измерять. Раз в сутки сохраняйте три числа: размер базы, свободное место на диске и количество выполнений в статусах running, new и waiting. Через две недели у вас появится график, и вопрос «когда кончится диск» превратится из тревоги в деление: свободное место на средний суточный прирост.
Порог для оповещения лучше привязывать не к проценту заполнения, а к оставшимся дням. Сообщение «осталось двенадцать суток при текущем росте» полезнее, чем «диск заполнен на 80%»: первое говорит, сколько у вас времени, второе только пугает. Простой сценарий в самом n8n может читать эти значения и присылать сообщение в мессенджер. Если у вас уже есть регулярные отчёты по базе, как в материале о ежедневном отчёте на PostgreSQL и n8n, добавьте строку про размер базы в тот же утренний поток.
После изменения политики проверьте три вещи. Во-первых, в течение недели прирост действительно замедлился и график вышел на плато, а не продолжает расти. Во-вторых, старые завершённые записи ушли, а ожидающие остались и вы о них знаете. В-третьих, свежая копия базы восстанавливается на отдельной тестовой машине вместе с ключом шифрования. Только тогда можно говорить, что порядок наведён.
Что останется для расследования завтра
Очистка всегда выбирает, чему из прошлого позволено исчезнуть. Поэтому закончить стоит вопросом, с которого начинается любой разбор: что вы сможете выяснить завтра, когда сегодняшняя очистка уже отработает?
Если политика построена правильно, ответ такой. Все ошибки за выбранный срок останутся вместе с узлом, на котором всё оборвалось, и его входными данными. Успешные запуски важных сценариев будут доступны достаточно долго, чтобы сверить их с отчётами и платежами. Ожидающие и зависшие записи никуда не денутся и будут видны в вашей еженедельной сводке. А рутинные успешные проверки исчезнут, и вместе с ними исчезнет только шум.
Помните, что очистка не архив. Если запись нужна как доказательство, например что письмо клиенту ушло именно с такими данными, её надо сохранять отдельно и намеренно, а не надеяться, что она переживёт срок хранения. Всё остальное история может отдавать без сожалений: диск, который вовремя освободил место, дороже сотен тысяч записей о том, что ничего не случилось.