Postgres и n8n: idempotency, журнал событий и безопасные SQL-операции ¶
Обновлено: 2026-05-30
Используйте JSON как основу: замените credentials, URL порталов, поля CRM и правила дедупликации.
Проблема: Без Postgres многие n8n-workflow держатся на памяти, Google Sheets или надежде, что webhook не повторится. После рестарта кэш исчезает, платеж обрабатывается второй раз, а ошибка API оставляет непонятный полуготовый статус.
Решение: использовать Postgres как durable-слой: таблица событий с unique key, журнал обработок, UPSERT вместо слепого INSERT, транзакционные статусы, отдельные роли с минимальными правами и понятный cleanup старых execution/event records.
Проблема: почему n8n без Postgres теряет надёжность на webhook и платежах ¶
Webhook-и, платежи, CRM-события и AI-задачи не обязаны приходить один раз. Они могут повторяться, приходить не по порядку или падать на середине обработки. Если workflow не пишет состояние в durable storage, он не знает, что уже сделал: создал сделку, отправил письмо или начислил доступ.
Postgres нужен не только как база n8n. Это отдельный операционный слой для интеграций: unique index останавливает дубли, журнал событий помогает расследовать инциденты, а статусная модель позволяет безопасно повторять обработку после сбоя.
Архитектура Postgres-слоя для n8n workflow ¶
| Блок | Задача | Production-проверка |
|---|---|---|
| Webhook input | принимает событие от CRM, оплаты или сайта | event_id/source в payload |
| Build idempotency key | создаёт стабильный ключ обработки | source + event_id + action |
| Insert event log | пишет событие в Postgres | unique index, ON CONFLICT |
| Process business action | обновляет CRM/API/почту | только если событие новое |
| Mark processed | фиксирует результат и timestamps | status, attempts, error_message |
| Cleanup and monitoring | чистит старые записи и ловит ошибки | retention, slow query, alert |
Для критичных сценариев не храните только “последний статус”. Нужен event log: что пришло, какой ключ был использован, какое действие выполнено и чем закончилась обработка.
Контракт webhook-события для записи в Postgres ¶
{
"source": "yookassa",
"event_id": "2f3c6a99-000f-5000-9000-1d2a3b4c5d6e",
"event_type": "payment.succeeded",
"entity_id": "order-10492",
"action": "mark_paid",
"received_at": "2026-05-30T10:00:00Z",
"payload": {
"amount": "12900.00",
"currency": "RUB"
}
}
Ключ event_id должен приходить от внешней системы. Если его нет, собирайте hash из source, entity_id, action и нормализованного timestamp, но документируйте риск коллизий.
Code Node: idempotency key и SQL parameters ¶
const src = $json.body ?? $json;
const source = String(src.source ?? 'unknown').trim().toLowerCase();
const eventId = String(src.event_id ?? src.id ?? '').trim();
const action = String(src.action ?? src.event_type ?? 'process').trim().toLowerCase();
if (!source || !eventId) throw new Error('Postgres idempotency requires source and event_id');
const key = `${source}:${eventId}:${action}`;
return [{ json: {
idempotency_key: key,
source,
event_id: eventId,
action,
entity_id: String(src.entity_id ?? ''),
status: 'received',
payload_json: JSON.stringify(src),
received_at: new Date().toISOString(),
insert_sql: `insert into integration_events (idempotency_key, source, event_id, action, entity_id, status, payload_json, received_at) values ($1,$2,$3,$4,$5,$6,$7,$8) on conflict (idempotency_key) do nothing returning id`,
params: [key, source, eventId, action, String(src.entity_id ?? ''), 'received', JSON.stringify(src), new Date().toISOString()]
}}];
Минимальная SQL-схема для idempotency
Таблица integration_events должна иметь primary key/id, уникальный idempotency_key, source, event_id, action, status, attempts, payload_json, timestamps и поле error_message для диагностики.
Готовый workflow JSON: скачать и импортировать ¶
Скачать готовый workflow JSON Скачать тестовый payload
{
"name": "Nodbot - Postgres n8n idempotency and event log blueprint",
"nodes": [
{
"name": "Webhook input",
"type": "n8n-nodes-base.webhook",
"purpose": "Получить внешнее событие"
},
{
"name": "Build idempotency key",
"type": "n8n-nodes-base.code",
"purpose": "Собрать стабильный ключ и SQL parameters"
},
{
"name": "Insert event log",
"type": "n8n-nodes-base.postgres",
"purpose": "Вставить событие через ON CONFLICT DO NOTHING"
},
{
"name": "Process only new event",
"type": "n8n-nodes-base.if",
"purpose": "Продолжить только если событие новое"
},
{
"name": "Business action",
"type": "n8n-nodes-base.httpRequest",
"purpose": "Выполнить CRM/API-действие"
},
{
"name": "Mark processed",
"type": "n8n-nodes-base.postgres",
"purpose": "Обновить status/attempts/error"
}
],
"connections": "Webhook input → Build idempotency key → Insert event log → Process only new event → Business action → Mark processed"
}
Пошаговая настройка Postgres node, таблиц и прав ¶
- Создайте отдельную базу или schema для integration event log.
- Добавьте таблицу
integration_eventsс unique index поidempotency_key. - Создайте Postgres-роль с минимальными правами только на нужные таблицы.
- Импортируйте workflow JSON и настройте Postgres credential в n8n.
- Добавьте cleanup job и alert на ошибки insert/update или slow query.
Тесты перед production ¶
curl -X POST "https://YOUR-N8N-DOMAIN/webhook/integration-postgres-n8n" \
-H "Content-Type: application/json" \
--data @integration-postgres-n8n-payload.json
- Отправьте один payload дважды и проверьте, что бизнес-действие выполнено один раз.
- Отключите внешний API после insert и проверьте status/error_message.
- Проверьте, что Postgres credential не имеет прав на системные таблицы.
- Сымитируйте параллельные запросы с одним ключом.
- Проверьте retention: старые события удаляются или архивируются по правилу.
Production-риски ¶
- Идемпотентность в памяти. После рестарта n8n повторная обработка снова станет возможной.
- INSERT без unique index. Проверка в IF не защитит от гонок при параллельных webhook.
- SQL из строковой конкатенации. Используйте parameters, а не склейку пользовательского текста.
- Слишком широкие права. Workflow не должен иметь owner/superuser-доступ.
- Нет cleanup. Журнал событий растёт бесконечно и замедляет запросы.
Полезные ссылки и смежные материалы ¶
- n8n Postgres node
- PostgreSQL INSERT / ON CONFLICT
- Workflow: webhook idempotency to Postgres
- Postgres для self-hosted n8n
- Backup и restore Postgres
Критерии готовности ¶
- Есть unique index по idempotency_key.
- Бизнес-действие выполняется только для новой записи.
- SQL использует параметры, а не строковую склейку.
- Права Postgres credential ограничены.
- Есть cleanup, backup и alert на ошибки БД.
Nodbot настроит Postgres-слой для n8n: event log, idempotency, безопасные SQL-запросы, роли, backup и мониторинг.
Обсудить Postgres-интеграцию