- Добавлены unified_id и contact_id в TicketFormDescriptionRequest - Исправлен CODE_MERGE_PROJECT_TO_SESSION.js - теперь сохраняются ВСЕ данные из body.other - Добавлен fallback на получение other из Webhook напрямую - Генерация новой session_id при создании новой жалобы (сохраняя авторизацию) - Добавлен SQL_SELECT_CONTACT_WITH_CUSTOM_FIELDS.sql для CRM контактов - Создан SESSION_LOG_2025-11-25.md с документацией сессии
145 lines
5.0 KiB
Python
Executable File
145 lines
5.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
"""
|
||
Мониторинг Redis Trigger в n8n
|
||
Проверяет наличие подписчиков на канале ticket_form:description
|
||
и отправляет алерт если подписчиков нет
|
||
"""
|
||
import redis
|
||
import time
|
||
import logging
|
||
from datetime import datetime
|
||
import sys
|
||
|
||
# Настройки
|
||
REDIS_HOST = "crm.clientright.ru"
|
||
REDIS_PORT = 6379
|
||
REDIS_PASSWORD = "CRM_Redis_Pass_2025_Secure!"
|
||
CHANNEL = "ticket_form:description"
|
||
CHECK_INTERVAL = 60 # Проверка каждую минуту
|
||
ALERT_THRESHOLD = 0 # Если подписчиков меньше этого значения - алерт
|
||
|
||
logging.basicConfig(
|
||
level=logging.INFO,
|
||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||
handlers=[
|
||
logging.FileHandler('/var/www/fastuser/data/www/crm.clientright.ru/ticket_form/logs/n8n_redis_monitor.log'),
|
||
logging.StreamHandler(sys.stdout)
|
||
]
|
||
)
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
def check_subscribers():
|
||
"""Проверка количества подписчиков на канале"""
|
||
try:
|
||
r = redis.Redis(
|
||
host=REDIS_HOST,
|
||
port=REDIS_PORT,
|
||
password=REDIS_PASSWORD,
|
||
decode_responses=True,
|
||
socket_connect_timeout=5,
|
||
socket_timeout=5
|
||
)
|
||
|
||
# Проверка подключения
|
||
r.ping()
|
||
|
||
# Проверка подписчиков
|
||
numsub = r.pubsub_numsub(CHANNEL)
|
||
subscribers = numsub[0][1] if numsub else 0
|
||
|
||
logger.info(f"📊 Канал {CHANNEL}: {subscribers} подписчиков")
|
||
|
||
if subscribers <= ALERT_THRESHOLD:
|
||
logger.warning(
|
||
f"⚠️ ВНИМАНИЕ: На канале {CHANNEL} нет подписчиков! "
|
||
f"n8n workflow может быть неактивен или завис."
|
||
)
|
||
return False
|
||
|
||
return True
|
||
|
||
except redis.ConnectionError as e:
|
||
logger.error(f"❌ Ошибка подключения к Redis: {e}")
|
||
return False
|
||
except Exception as e:
|
||
logger.error(f"❌ Неожиданная ошибка: {e}")
|
||
return False
|
||
finally:
|
||
try:
|
||
r.close()
|
||
except:
|
||
pass
|
||
|
||
|
||
def send_test_message():
|
||
"""Отправка тестового сообщения для проверки"""
|
||
try:
|
||
r = redis.Redis(
|
||
host=REDIS_HOST,
|
||
port=REDIS_PORT,
|
||
password=REDIS_PASSWORD,
|
||
decode_responses=True,
|
||
socket_connect_timeout=5,
|
||
socket_timeout=5
|
||
)
|
||
|
||
test_message = {
|
||
"type": "test",
|
||
"session_id": "monitor_test",
|
||
"timestamp": datetime.utcnow().isoformat(),
|
||
"message": "Health check from monitor script"
|
||
}
|
||
|
||
import json
|
||
subscribers = r.publish(CHANNEL, json.dumps(test_message))
|
||
logger.info(f"📤 Тестовое сообщение отправлено. Получено подписчиками: {subscribers}")
|
||
|
||
r.close()
|
||
return subscribers > 0
|
||
|
||
except Exception as e:
|
||
logger.error(f"❌ Ошибка отправки тестового сообщения: {e}")
|
||
return False
|
||
|
||
|
||
def main():
|
||
"""Основной цикл мониторинга"""
|
||
logger.info("🚀 Запуск мониторинга Redis Trigger для n8n")
|
||
logger.info(f"📡 Канал: {CHANNEL}")
|
||
logger.info(f"⏱️ Интервал проверки: {CHECK_INTERVAL} секунд")
|
||
|
||
consecutive_failures = 0
|
||
max_failures = 3 # После 3 неудачных проверок подряд - критический алерт
|
||
|
||
while True:
|
||
try:
|
||
is_ok = check_subscribers()
|
||
|
||
if is_ok:
|
||
consecutive_failures = 0
|
||
else:
|
||
consecutive_failures += 1
|
||
|
||
if consecutive_failures >= max_failures:
|
||
logger.critical(
|
||
f"🚨 КРИТИЧЕСКОЕ СОСТОЯНИЕ: "
|
||
f"Канал {CHANNEL} не имеет подписчиков уже {consecutive_failures} проверок подряд! "
|
||
f"Требуется перезапуск n8n workflow!"
|
||
)
|
||
# Можно добавить отправку уведомления (email, telegram, etc.)
|
||
|
||
time.sleep(CHECK_INTERVAL)
|
||
|
||
except KeyboardInterrupt:
|
||
logger.info("⏹️ Остановка мониторинга по запросу пользователя")
|
||
break
|
||
except Exception as e:
|
||
logger.error(f"❌ Критическая ошибка в цикле мониторинга: {e}")
|
||
time.sleep(CHECK_INTERVAL)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|
||
|