Telegram-боты для автоматизации ITSM: от единого стиля оповещений к команде ботов

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Привет, я Максим Королев из Петрович-ТЕХ, занимаюсь уровнем сервиса. Моя роль — в том числе про “как хороший сервис показать пользователю, чтобы тот не отказался от нового/сложного/страшного инструмента”.

Было так: не все пользователи ходили в техническую поддержку по “правильному” маршруту, через портал. Из-за этого мы теряли случаи, составляющие общую картину проблем, и озадачились: как упростить пользователям заход в поддержку?

Решили сделать семейство Telegram-ботов, которые сократили время на создание повторяющихся задач на 50–70%, подняли заполняемость до 100%, ускорили реакцию на инциденты.

Если в новом году хотите запилить много микроавтоматизаций через боты, наш кейс к вашему столу: вот как вышло у Петрович-ТЕХа.

Персонификация: заботимся о качестве бота правильной мотивацией разработки

Первого бота зовут Славик. Когда мы начали его создавать, написание кода, проверка скриптов и работа над ошибками были абстрактными. А потом мы придумали ему лицо — портрет осьминога, эдакого маскота функции. На обложке статьи как раз он.

Получилось, что теперь код мы пишем для Славика. Если допустить ошибку — страдает он, конкретный осьминог, а не просто «бот номер один». Это изменило нашу ответственность. Код стал качественнее, тесты серьёзнее, обработка ошибок внимательнее.

Решили дать имена и остальным ботам. Когда у каждого есть история и лицо — разработка становится созданием чего-то живого. Чуть алхимии реально помогает делать лучший код.

Это Славик, наш первый бот
Это Славик, наш первый бот

Архитектура и общие принципы

Все наши боты построены на общих принципах, которые дают быстро развить функционал под запрос и поддерживать код в актуальном состоянии.

Слоистая архитектура

Мы используем подход, близкий к Clean Architecture, с разделением на слои:

Transport Layer (Telegram Bot API)

  • Обработчики команд и сообщений

  • FSM для управления диалогами

  • Валидация входных данных

Application Layer (Use Cases)

  • Бизнес-логика создания задач

  • Обработка сценариев (регистрация, создание заявки)

  • Координация между слоями

Domain Layer (Бизнес-сущности)

  • Модели данных (User, Ticket, Failure)

  • Бизнес-правила и валидация

  • Value Objects (Priority, Status)

Infrastructure Layer (Внешние интеграции)

  • JIRA API клиент

  • Хранилища данных (JSON, PostgreSQL)

  • Службы уведомлений

Такое разделение позволяет легко менять детали реализации без влияния на бизнес-логику.

FSM для управления диалогами

Все многошаговые сценарии (регистрация, создание заявки) реализованы через Finite State Machine (FSM) из aiogram. Это чтобы четко контролировать последовательность шагов, сохранять промежуточные данные, легко добавлять новые шаги или изменять их порядок и обрабатывать отмену на любом этапе.

Пример структуры состояний для создания заявки:

class SearchFormStates(StatesGroup):
    SELECT_PROBLEMATIC_SERVICE = State()  # Шаг 1: Выбор сервиса
    SELECT_REQUEST_TYPE = State()         # Шаг 2: Тип запроса
    ENTER_CITY = State()                  # Шаг 3: Город
    ENTER_COMMENT = State()               # Шаг 4: Комментарий
    UPLOAD_ATTACHMENT = State()           # Шаг 5: Файл
    CONFIRM_AND_CREATE = State()          # Шаг 6: Подтверждение

Хранение состояния

Для небольших ботов (до 100 активных пользователей) используем JSON-файлы с thread-safe блокировками (RLock). Это просто и достаточно быстро.

Для масштабирования переходим на:

  • In-memory кэш с TTL для часто запрашиваемых данных

  • PostgreSQL для персистентного хранения

  • Redis для распределенных блокировок (если нужно)

Обёртка над JIRA REST API

Все боты используют единый модуль для работы с JIRA. Это даёт:

  • Единообразную обработку ошибок

  • Retry-механизм с экспоненциальной задержкой

  • Кэширование метаданных (типы задач, поля, transitions)

  • Логирование всех запросов

Пример: метод создания задачи из общего модуля JIRA. Показывает, как обрабатываем ошибки, логируем запросы и делаем retry. 

@handle_jira_errors
async def create_issue(self, issue_data: dict) -> JiraIssue:
    """Создает новую задачу в JIRA с retry и логированием"""
    if not self.session:
        raise JiraConnectionError("Сессия не инициализирована")
    
    # Логируем запрос для отладки
    logger.info(f"Создание задачи: {issue_data.get('fields', {}).get('summary')}")
    
    max_retries = 3
    for attempt in range(max_retries):
        try:
            async with self.session.post(
                f"{self.base_url}/issue",
                json=issue_data,
                timeout=self.config.REQUEST_TIMEOUT
            ) as response:
                # Проверяем статус ответа
                if response.status == 200:
                    data = await response.json()
                    logger.info(f"Задача создана: {data.get('key')}")
                    return data
                elif response.status == 429:  # Rate limit
                    # Экспоненциальная задержка
                    wait_time = (2 ** attempt) * 2
                    logger.warning(f"Rate limit, ждём {wait_time} сек")
                    await asyncio.sleep(wait_time)
                    continue
                else:
                    # Другие ошибки — пробрасываем дальше
                    text = await response.text()
                    raise JiraError(f"HTTP {response.status}: {text}")
        
        except asyncio.TimeoutError:
            if attempt < max_retries - 1:
                logger.warning(f"Timeout, попытка {attempt + 1}/{max_retries}")
                await asyncio.sleep(2 ** attempt)
                continue
            raise JiraConnectionError("Превышено время ожидания ответа от JIRA")
    
    raise JiraError("Не удалось создать задачу после всех попыток")

• Декоратор @handle_jira_errors централизует обработку ошибок

• Retry только для временных ошибок (429, timeout)

• Экспоненциальная задержка не перегружает JIRA

• Логирование помогает отлаживать проблемы в production

Безопасность

  • Все чувствительные данные в .env файлах

  • Токены никогда не коммитятся в Git

  • Используем python-dotenv для загрузки переменных окружения

  • Whitelist пользователей

  • Система регистрации с модерацией

  • Роли и права доступа 

  • Rate limiting для защиты от спама (3 команды/сек)

  • Все входные данные проверяются перед обработкой

Великолепная шестерка ботов

Теперь сами боты. Опишу их по схеме: задача — функция бота — из чего бот собран — пример кода — лайфхаки реализации — результаты.

"Лупа" — репортинг ошибок поиска в JIRA

Задача: сотруднику нужно быстро зафиксировать баг в поиске на сайте или приложении — не отвлекаясь от работы.

Что делает:

  • Интерактивная форма создания задачи — выбор сервиса, тип проблемы, город

  • Обязательная загрузка файла (фото/видео, до 10 МБ)

  • Автоматическое заполнение всех полей в JIRA

  • Логирование в Excel для статистики

Технически:

  • aiogram 3.x с FSM (Finite State Machine)

  • Асинхронная архитектура

  • Кэширование подразделений из JIRA

  • Валидация номеров и защита от дублей

Пример: это обработчик шага выбора сервиса в "Лупе". Показывает, как валидируем ввод, сохраняем данные и переходим к следующему шагу.

@router.callback_query(F.data.startswith("service_"))
async def process_service_selection(
    callback: CallbackQuery, 
    state: FSMContext
):
    """Обработка выбора проблемного сервиса"""
    user_id = callback.from_user.id
    service = callback.data.replace("service_", "")
    
    # Сохраняем выбранный сервис в состоянии
    await state.update_data(problematic_service=service)
    
    # Переходим к следующему шагу
    await state.set_state(SearchFormStates.SELECT_REQUEST_TYPE)
    
    # Показываем клавиатуру с типами запросов
    await callback.message.edit_text(
        "Выберите тип запроса:",
        reply_markup=create_request_type_keyboard()
    )
    await callback.answer()

• Используем callback_query для кнопок — это надёжнее, чем текстовый ввод

• Сохраняем данные в state перед переходом — если пользователь отменит, данные не потеряются

• Используем edit_text вместо нового сообщения — меньше спама в чате

Результаты:

  • 30+ задач за первый месяц

  • Время создания задачи: 5-10 мин → 2-3 мин (-60%)

  • 100% корректное заполнение полей

 "Рафтар" — сбор статусов проектов

Задача: собрать ежемесячный статус для контроля жизненного цикла 50+ проектов.

Что делает:

  • Пошаговый мастер заполнения

  • Блокировка повторного заполнения в течение месяца

  • Автоматическое создание RAF-задач в JIRA

  • Система напоминаний: ежемесячная рассылка + ежедневные пуш-напоминания + финальное уведомление

  • Excel-отчеты

Технически:

  • Планировщик задач (scheduler) для автоматических напоминаний

  • Умный поиск transitions в JIRA

  • Система отслеживания напоминаний (JSON)

Пример: это фрагмент планировщика из "Рафтара". Показывает, как формируется задание “напоминание” и как храним состояние.

class StatusReminderScheduler:
    """Планировщик для автоматических напоминаний"""
    
    def __init__(self, bot: Bot):
        self.bot = bot
        self.is_running = False
    
    async def send_monthly_reminders(self):
        """Отправка месячных напоминаний в первый рабочий день"""
        period = get_current_period()  # "Октябрь 2024"
        
        # Загружаем базу напоминаний
        db = load_reminders_db()
        
        # Получаем всех пользователей с активными проектами
        all_projects = get_all_projects()
        users_with_projects = set()
        for project in all_projects.values():
            users_with_projects.update(project.get("users", []))
        
        sent_count = 0
        for user_id in users_with_projects:
            # Проверяем, не заполнены ли уже статусы
            if check_status_exists(user_id, period):
                continue
            
            # Отправляем напоминание
            try:
                await self.bot.send_message(
                    user_id,
                    f"						
Источник: https://habr.com/ru/companies/petrovich-tech/articles/985474/


Интересные статьи

Интересные статьи

С развитием искусственного интеллекта, всё больше пользователей и компаний используют нейросети. Меня, как дизайнера, интересуют сети, способные генерировать изображения по текстовому описанию. А поск...
Привет, меня зовут Евгений, я разработчик из Байовэр в компании НЛМК ИТ.Довелось мне тут столкнуться с разработкой системы опытно-промышленных испытаний на производстве, и если описать это к...
Привет, Хабр! Меня зовут Макс Баюров, я PHP-разработчик в компании AGIMA. Мне хотелось бы поделиться с вами опытом расширения уровней доступа к функционалу сайта. Если вам еще не приходилось с этим ст...
Статья предполагает, что читатель имеет опыт работы с интерактивным программным средством доказательства теорем — Coq.Статья является адаптированной русскоязычной версией моей статьи, написанной во вр...
Привет! На связи Данила Соловьев, руководитель направления PHP в AGIMA. Для проджект-менеджеров и джуниор-разработчиков я подготовил небольшой гайд по тому, как ускорять работу крупных проектов на Бит...