TimescaleDB и Grafana: события CRM и оповещения о задержках

TimescaleDB и Grafana: события CRM и оповещения о задержках

Обновлено 2 сентября 2026 года.

TimescaleDB расширяет PostgreSQL инструментами для временных рядов. Grafana может читать подготовленные данные и проверять условия оповещений. Для CRM полезно разделить две задачи: график количества событий по времени и поиск открытых сделок без контакта с клиентом. Им нужны разные модели данных.

Сначала определите, что считать активностью

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

У события должны быть стабильный ключ, ключ сделки, тип и время события. Отдельно храните время получения. Повторная доставка не должна увеличивать счётчик. Для hypertable проверьте ограничения уникальных индексов: ключ должен учитывать колонки разбиения по времени. Политику повторов и событий с изменённой датой нужно спроектировать до загрузки.

Агрегат для графика

Предположим, что расширение установлено, схема metrics создана, а raw.deal_activity — уже заполненная hypertable с временной колонкой occurred_at. Для количества событий по часам можно определить:

CREATE MATERIALIZED VIEW metrics.activity_hourly
WITH (timescaledb.continuous) AS
SELECT
  time_bucket(INTERVAL '1 hour', occurred_at) AS bucket,
  count(*) AS event_count
FROM raw.deal_activity
GROUP BY bucket
WITH NO DATA;

Continuous aggregate требует time_bucket по временной колонке. Простое GROUP BY deal_id с max(occurred_at) не является заменой этому требованию. WITH NO DATA оставляет материализованный результат незаполненным: нужен первоначальный refresh, затем подходящая политика обновления.

Согласуйте диапазон пересчёта с опоздавшими событиями. Если политика исключает последний час, не рассчитывайте получить из одной материализованной части точную картину последних 30 минут. Для свежего интервала нужен явно выбранный способ чтения ещё не материализованных данных. Доступность и поведение real-time aggregation проверяйте для установленной версии.

Отдельная модель для «забытых» сделок

Подготовьте таблицу текущих сделок mart.deals_current: одна строка на сделку, поля deal_id, is_open, created_at, last_contact_at. Эти имена описывают учебную витрину. last_contact_at рассчитывается по выбранным контактам, а не по произвольному редактированию карточки. Для сделок без контактов началом ожидания в примере служит дата создания.

SELECT count(*)::double precision AS overdue_deals
FROM mart.deals_current
WHERE is_open
  AND coalesce(last_contact_at, created_at)
      < now() - interval '3 days';

Запрос возвращает одну числовую величину, в том числе ноль, когда просроченных сделок нет. Проверьте обязательность created_at и бизнес-правило: три календарных дня отличаются от трёх рабочих дней. Детальный список сделок для менеджера оформите отдельной таблицей.

Читай также:  Airflow → PostgreSQL → dbt → Superset: надёжная загрузка

Оповещение Grafana

Подключите PostgreSQL ролью чтения витрины. В правиле используйте числовой результат, порог и интервал проверки, согласованные с бизнесом. Например, порог больше 10 сделок и ожидание 10 минут — лишь учебная настройка, а не универсальная норма. Настройте адресата и проверяйте доставку тестовым событием.

No Data и Error в Grafana требуют осмысленной обработки. Не назначайте им состояние «всё нормально» только для подавления уведомлений. Исправный запрос со значением 0 и отсутствие данных — разные ситуации.

Дополнительно контролируйте свежесть загрузки: запрос может успешно вернуть ноль из давно не обновлявшейся базы. Повторные уведомления регулируйте политикой группировки и повторения; параметр Keep firing for задаёт поведение восстановления состояния, а не универсальное подавление дублей.

Проверка перед запуском

Создайте открытые сделки с недавним контактом, давним контактом и без контактов, а также закрытую сделку. Сверьте состав просроченных вручную. Повторите загрузку события, имитируйте задержку и остановку источника. Восстановление должно обновить и витрину, и состояние оповещения.

TimescaleDB не гарантирует заданную скорость без измерений. Настройки памяти, фоновых процессов, хранения и резервного копирования выбирают для вашей нагрузки. Ошибка «таблица уже hypertable» сама по себе не является поводом удалять рабочую схему.