Как мы разрабатывали бота в мессенджере eXpress для 1-й линии поддержки
Привет, уважаемые читатели Хабра!
На связи Лаборатория инноваций Московской биржи.
Хотим поделиться с вами нашим опытом разработки чат-бота для 1-й линии поддержки на базе корпоративного мессенджера eXpress.
Расскажем о нашем опыте, ошибках, сделанных выводах и поделимся полезными ссылками для желающих заняться разработкой ботов для eXpress.
Примечание: учтите, что доступ к ботам в eXpress предоставляется только корпоративным клиентам.
Итак, приступим.
В компаниях с 0 толерантностью к риску, таких как Московская биржа, даже самые простые инициативы требуют специального подхода, внимательного рассмотрения и согласования со Службой информационной безопасности (далее по тексту — СИБ) каждого этапа.
Нашей команде поступила задача купить/придумать/разработать простой инструмент, который позволил бы бизнес-пользователям, у которых нет прямого доступа к корпоративному тасктрекеру (далее по тексту ТТ), получать статус по своим заявкам без необходимости дополнительного обращения к первой линии поддержки. Изначально мы рассматривали возможность использования телеграм-бота, но выяснилось, что такое решение не подходит по ряду технических причин:
Оно должно быть доступно из контура, откуда нет свободного выхода в интернет.
Информация в заявках может быть «чувствительной» и хорошо бы, чтобы она оставалась в пределах компании.
Вместо этого мы приняли решение разработать бота в eXpress. Их бот-платформа схожа по архитектуре с Телеграмом. Учитывая популярность языка Python и его обширное использование в различных областях, для написания бота мы выбрали именно его. Мы также рассчитывали на активное сообщество специалистов и доступный бюджетный фонд, ведь нашей целью была реализация MVP и передача бота заказчику в течение нескольких недель.
Однако результат показал, что мы сильно заблуждались.
После нескольких переговоров с заказчиком мы утвердили схему бота (ниже), но столкнулись с серьезными техническими трудностями.
Схема бота
Т.к. мы хотели напрямую из бота ходить по API к нашему ТТ и забирать данные о заявках, это стало серьёзным ограничением как с точки зрения СИБ, так и с точки зрения самой реализации. В ходе переговоров и чтения документации выяснилось, что API ТТ не готов отдавать нам всё, что было нужно для данного кейса, и требовалось потратить несколько недель на выполнение доработок. Нас это не устроило и поэтому, на смену работы с ТТ по API, пришло решение работать через представления в БД (оказалось, это куда проще и безопаснее сделать) и работу с представлениями было принято вести не напрямую из бота, а через специальный сервер внутри контура, который будет выполнять роль фильтра.
Во-первых, он будет авторизовывать запрос от бота, и это даст своеобразную гарантию, что к сервису нельзя будет получить доступ другим способом.
Во-вторых, проверять, что у обращающегося от имени бота есть доступ к данному сервису.
В процессе диалога с коллегами из испытательной лаборатории по информационной безопасности мы разработали интеграционную схему и отказались от некоторых решений, которыми первоначально хотели воспользоваться.
Первая версия интеграционной схемы выглядела так:
Но СИБ такую схему не утвердили, т.к. в ней недоставало деталей. На последнюю версию схемы мы нанесли названия сетей, подсетей, систем, IP-адреса и порты и сетевую схему взаимодействия. К тому же, доступ к нашему Application REST API реализован не через Gravitee, а внутри VPN тоннеля посредством прямого подключения по HTTPS, что тоже нашло отражение на новой схеме.
После всех этапов согласований и утверждения плана реализации мы приступили к написанию кода для самого бота. При написании использовали библиотеку для создания чат-ботов и SmartApps для мессенджера eXpress pybotx (т.к. она простая в использовании и легко интегрируется с асинхронными фреймворками). Также у ребят из eXpress есть шаблон, в котором основной код для работы с библиотекой pybotx уже написан. В шаблоне используется fastapi, sqlalchemy, redis для конечных автоматов, psycopg для интеграции с PostgreSQL и библиотека для работы конечных автоматов. Шаблон разворачивается с помощью библиотеки copier, чем мы и воспользовались. В результате первая часть — сам бот, который развернут на бот-сервере в Express, готова. Осталась вторая часть сервиса — бэкенд бота, который развернут на внутреннем сервере Биржи. В нем будет происходить вся бизнес-логика: обработка команд, проверка прав, соединения с другими сервисами.
Первой трудностью, с которой мы столкнулись при разработке бэкенд части, стала банальная версионная несовместимость. В разработке бэкенда мы хотели использовать последний python, но не получилось, т.к. все нужно брать из корпоративного Nexus, а некоторых библиотек там вообще не оказалось, например fastapi-users. Пришлось остановиться на python версии 3.8, менять все версии библиотек в pyproject.toml под него, пересобирать poetry.lock и писать самим аутентификацию пользователей с JWT и хешированием паролей (спасибо документации FastAPI за подробный гайд)
Следующим фактором, с которым боролись не один день, стала сложность свместимости одновременно синхронного и асинхронного подключения к двум разным БД. Для работы с данными по заявкам на поддержку нам необходимо иметь соединение с базой данной MSSQL, находящейся на другом сервере, а для хранения пользовательских данных нужно соединение с базой данных PostgreSQL, находящейся рядом с приложением на одном сервере. Так как эндпоинты в приложении асинхронные, мы использовали асинхронное соединение с PostgreSQL с помощью create_async_engine в SQLAlchemy и библиотеки asyncpg. А вот для соединения с БД MSSQL в Nexus не оказалось асинхронной библиотеки, была только синхронная — pymssql.
Мы попробовали использовать обычный create_engine для соединения с MSSQL и засунули его в Depends:
К сожалению, это не сработало, при использовании параметра mssql_db в коде возникала ошибка cannot unpack non iterable coroutine object. Как мы поняли, проблема может быть связана с тем, что FastAPI ожидает, что все обработчики зависимостей (dependencies) будут асинхронными в асихронном эндпоинте.
Потом мы решили использовать run_in_executor из библиотеки asyncio, чтобы запустить
синхронный код в асинхронной функции:
И это сработало! Мы получили то, чего добивались.
В конечном итоге, после нескольких месяцев совместной усердной работы с коллегами, согласований и разработки мы получили работающего бота:
На весь проект ушло 4 месяца, вместо пары недель, на которые мы рассчитывали xD.
В ближайшие пару месяцев планируем проверить работоспособность бота на тестовой группе сотрудников Московской биржи: посмотрим, кто и как будет его использовать, какие запросы чаще всего будут отправляться. Далее, если бот будет пользоваться спросом — будем думать, как его масштабировать на всех сотрудников Группы MOEX.
Результатами поделимся с вами в следующих статьях.
ЗАКЛЮЧЕНИЕ
Этот опыт показал нам важность рассмотрения всех технических аспектов разработки, правильного планирования сроков, когда в проект вовлечены внешние вендоры и есть процессы согласования с несколькими подразделениями, внимательного подхода к интеграции с существующими системами и тщательного управления рисками. Мы уверены, что собранный опыт будет полезен другим разработчикам, приступающим к подобным задачам.
В завершение несколько общих советов (которые, кстати, можно применить к любому ИТ-проекту):
закладывайте время на возможные срывы сроков, форс-мажоры и уход ключевых разработчиков с проекта;
в планировании сроков реализации важное место отводите этапу согласования с СИБ;
продумывайте «план Б» на случай, если по основному плану всё пойдёт не так;
выявляйте и анализируйте требования заказчика в форме прецедентов использования;
описывайте предполагаемый бизнес-процесс;
моделируйте взаимодействия прецедентов и бизнес-процессов;
обращайте внимание на детали, фиксируйте всё письменно.
Благодарим за внимание и желаем удачи в ваших проектах!
P.S. А для тех, кто решит разрабатывать ботов в Express, список статей и материалов по их разработке ниже:
Статьи:
· https://docs.express.ms/chatbot-and-smartapp/developer-guide/getting-started/what-is-chatbot-and-smartapp/
· https://hackmd.ccsteam.ru/s/4IHk-iFDRБиблиотеки Бот-сервисов:
· https://github.com/ExpressApp/pybotx
· https://github.com/ExpressApp/async-box
· https://github.com/ExpressApp/pybotx-fsm
· https://github.com/ExpressApp/pybotx-smartapp-rpc
· https://github.com/ExpressApp/pybotx-smart-logger
· https://github.com/ExpressApp/pybotx-smartapp-smart-logger
· https://github.com/ExpressApp/smartapp-bridge
· https://github.com/ExpressApp/smartapp-sdk