Сегодня мы немного расскажем вам о работе IT-поддержки в Ozon Tech: что мы делаем и зачем, как используем Python, и как именно он нам помогает решать рутинные проблемы и не только. - Моральная поддержка мне не помешает.- Вот и отлично. Но я сразу предупреждаю: я не могу гарантировать моральность моей поддержки. © Для начала, пожалуй, стоит рассказать, что представляет собой IT-поддержка в Ozon Tech, а точнее о работе специалиста по поддержке внутренних сервисов в домене контента и товаров. Наша цель — собирать все технические проблемы, возникающие у клиентов при создании карточки товара, чтобы она прошла свой жизненный цикл, классифицировать обращения, проводить первичную аналитику, решать в моменте, заводить задачи на доработки функциональности, приоритизируя их по срочности, массовости и влиянию на бизнес-показатели.	К нам попадают задачи об ошибках в сервисах, в которых функциональность должна работать, но почему-то не работает. Разница между пользовательской поддержкой и нами — в инструментах и возможностях их использования в проде. Речь идёт о базах данных, HTTP- запросах, UI-админках и т. д. Карточки товаров могут не создаваться, контент — не обновляться. С этими и другими проблемами мы сталкиваемся в своей практике. Чтобы всё заработало как надо, и нужны эти инструменты. В общем и целом работа в команде IT-поддержки очень интересная. Это не только «Ну вы держитесь там!», но и решение разноплановых IT-задач, иногда связанных с обработкой больших объёмов данных. Какое-то время мы жили и не тужили, дёргая так называемые «ручки» в Swagger и используя Postman, селектили базки и т. д. Но сервисов становилось всё больше, появлялись новые фичи — следовательно, и количество проблем увеличивалось. Появилась необходимость больше селектить, делать больше HTTP-запросов, их комбинируя. Кроме того, появились задачи по анализу большого количества данных, где, например, за один раз не передашь все нужные ID, и запросы, от которых не то что база умирала — умирала DataGrip. Подобные задачи стали решаться очень долго  — и мы поняли, что пора что-то менять... может быть даже работу. Если провести аналогию с известной сказкой, нашей «золотой рыбкой» стал Python. К нам в команду пришёл человек, который перевернул наш подход к работе. Забегая вперёд, скажу, что последующий наём сотрудников в наш отдел был с пунктом о знании скриптовых языков и в частности Python и на текущий момент половина сотрудников пишет на нём, все умеют с ним работать, у нас реализован свой небольшой сервис, учитывающий требования информационной безопасности, а тимлиды используют язык в рамках проектного управления и аналитики проблем. Так мы очень быстро узнаём о болях клиентов и специфике работы того или иного сервиса. Подробнее об этом — ниже. Опытным коллегам, пишущим на Python, мы не раскроем каких-то сакральных тайн с точки зрения кода, а вот аналитикам, возможно, поможем усовершенствовать процессы. Ну поехали что-ли. Самым важным в нашей работе является использование HTTP-запросов. Это краеугольный камень нашей автоматизации. Мы завели сервисную учётку в Jira, сделав бота, который работает с API, избавляя нас от большого количества ручной работы. С помощью скрипта на Python мы решили несколько задач: дважды в день в определённое время проходить по всем созданным JIT-задачам в нашем капасити; проверять прилинкованные Jira-тикеты, считать их и обновлять их количество в JIT-задаче; оставлять комментарии; проверять правильность связи между JIT-задачей и Jira-тикетами. Кроме того, с помощью данного скрипта реализован подсчёт инструментов, которые используются при решении задач в течение определённого периода времени. Это позволяет нам выявлять самые популярные решения, определять боли клиентов и находить причины их возникновения, а затем устранять эти проблемы. На примере бота мы рассмотрим основные модули и библиотеки Python, которые мы используем в написании скриптов. В текущих реалиях работы с запросами... Модуль Requests нужен для отправки и получения данных. Чтобы выполнить HTTP-запрос, используется стандартный метод написания функции на Python. Так выглядит структура стандартной функции, которая используется во всех наших скриптах. В поле url мы указываем строку запроса, в поле headers — заголовки авторизации, а в payload — какие данные мы хотим отправить в теле запроса. Всё довольно стандартно, но, начитавшись статей про обработку ошибок в Golang, мы позаимствовали её, задав переменную error. И для удобства написали небольшую функцию, которая возвращает текст ошибки. Чтобы укротить время, мы воспользовались модулями datetime и time. По аналогии с ботом мы выполняли различные запросы, используя HTTP-методы отдельных сервисов. Чтобы в каждый запрос можно было отправлять не по одному значению, а, например, массив данных, был реализован цикл, который собирает массив (батчи) для отправки его в запрос. Про использование батчей другого типа формирования расскажем ниже на примере обращения к базе данных. Цикл формирует массив total, передаёт его в функцию, после получения ответа очищает массив и собирает новый. Для записи данных в файл мы использовали функцию open и метод write. В процессе написания скриптов мы собрали собственную библиотеку функций по вызову различных методов отдельных сервисов. Она позволила ускорить процесс написания скриптов на Python разной сложности. Excel — прекрасный инструмент для работы с информацией в виде таблицы. Он-то и пригодился нам для решения нетривиальных задач с большим количеством данных. Если требуется отсортировать или сопоставить данные, мы, скорее всего, пойдём в Excel. Если же нужно эти отсортированные данные брать из разных столбцов в рамках одной строки и передавать в какую-нибудь функцию, мы идём в pandas. Подробнее вы, конечно, можете прочитать в интернете, но, если коротко, pandas — это высокоуровневая библиотека Python, которая позволяет вытворять с файлами Excel такое, что некоторым даже не снилось. Именно эту библиотеку мы и стали использовать для решения наших задач. Сразу оговорюсь, что мы не использовали её в полном объёме, так как в этом не было необходимости. В основном нам нужно было считывать значения из XLS-файла и присваивать их переменным. Прочитав с помощью функции read_excel файл и присвоив значение переменной, мы обращаемся к методу to_dict, чтобы преобразовать данные в словарь, а параметр orient = 'records' позволяет класть данные в словарь в следующем виде: . Ещё одним важным аспектом использования Excel является парсинг файла дежурств в нашу внутреннюю систему управления инцидентами. Согласно расписанию дежурств, сервис рассылает оповещения об инцидентах дежурным сотрудникам. Для наших коллег мы строим график в SharePoint и, если нужно что-то обновить, скармливаем скрипту файл — и через минуту получаем обновлённое расписание дежурств в системе управления инцидентами. Как вы уже, наверное, догадались, для добавления информации мы используем API этой системы. Если ты сотрудник Ozon Tech, тебе это может быть интересно — добро пожаловать во внутренний мессенджер.  Любой уважающий себя разработчик хоть раз ходил в Kafka и работал с ней. Мы, конечно, не дотягиваем до их уровня, но себя тоже уважаем и с Kafka сталкиваемся регулярно. Основные наши действия в Kafka — это чтение и запись. И для этого в Python есть модуль Confluent Kafka. Для отправки сообщений в Kafka мы использовали метод Producer. Алгоритм действий: подключаемся к Kafka через Producer({'bootstrap.servers': 'server'}); создаём массив данных (сообщений) с помощью create_data(file_name); отправляем сообщение в топик Kafka и ждём результат — produce.produce('topik_name', json.dumps(data), callback=delivery_report). Для того чтобы читать сообщения из Kafka, использовали метод Consumer. 'auto.offset.reset' указывает, в каком порядке читать сообщения: earliest — с самого раннего, latest — с последнего. Использование скриптов для выполнения запросов к базе данных — вишенка на торте, учитывая, что нельзя сделать всё через HTTP-методы, а потому частенько приходится селектить. Для работы с PostgreSQL мы использовали, наверное, самую популярную в Python библиотеку Psycopg2. Её модули и функции позволили нам выполнять подключение к базе данных, отправлять запросы и получать нужные результаты. Для подключения к базе данных мы написали функцию, в которой содержится информация о базе, к которой мы собираемся подключиться, и о пользователе, который будет выполнять подключение, а также переменную connection. Метод cursor(cursor_factory=extras.DictCursor) позволяет формировать полученные в ответе поля базы в виде словаря. Реализация запроса в базу данных: Иногда нужно сделать просто огромную выгрузку по тяжелому запросу. У нас есть любимая команда разработки, у сервиса которой есть выделенная архивная реплика, на которой нет клиентов, и её можно селектить сколько душе угодно. Вы, наверное, спросите, почему не использовать для больших аналитических запросов DWH? Можно, но есть необходимость получить данные в реальном времени, в отличие от DWH, в которой данные синхронизируются с некоторой периодичностью. У архивной реплики есть минус: если ей скормить долгий по ответу запрос, через некоторое время она начнёт отставать от мастера и данные станут неконсистентными. Поэтому, чтобы мы могли комфортно получать корректные значения в моменте, мы селектим через Python, используя батчи. Стараемся формировать их так, чтобы ответ занимал не более 200 мс, особенно если обращаться не к архивной реплике, так как она есть не у всех. О том, как формировать батчи по списку ID, мы писали в разделе про HTTP-методы. Но бывают случаи, когда есть какое-то условие и нет входных данных. Для них мы реализовали функцию формирования батчей от минимального до максимального ID (чаще всего по ключу) нужной таблицы. Минимальный ID всегда можно указать опционально. Максимальный — формируется через обычный запрос на получение в таблице. Ну а ненужные данные отсекаются внутри условия запроса. В Ozon Tech много микросервисов — и кто-то должен их поддерживать. Система несовершенна, а значит, случаются ошибки. Как писал наш коллега Игорь в статье, прод имеет свойство падать и после этого иногда нужно исправлять данные, с которыми что-то произошло. Прокачав скиллы в Python, мы помогаем в этом коллегам. Кроме того, есть частные случаи ошибок, ведь, являясь MVP, продукт подразумевает проверку на жизнеспособность, так как она минимальна.  И тут мы, как поддержка, можем собрать фидбэк, найти ошибки, исправить их в моменте, провести анализ и создать задачу на устранение первопричины. А можно этот процесс сравнить с химией: проблемы, которые мы находим, — это «лакмусовая бумажка» работы системы или сервиса. Команд разработок в нашем домене много, микросервисов ещё больше — и со всем этим надо жить. А Python со своими прекрасными модулями, библиотеками и функциями позволил нам написать скрипты, которые очень помогают в решении многих непростых задач, с которыми команда IT-поддержки сталкивается каждый день. Освоив это ремесло, мы значительно уменьшили нагрузку на команды разработки, что позволило им погружаться в глубины мироздания, не отвлекаясь на рутину, и пилить новые фичи для бизнеса, а мы в свою очередь почувствовали себя ещё более крутыми IT-специалистами. Ведь наша главная цель — чтобы всем клиентам было удобно и легко работать на нашей площадке! Авторы:Сергей Исаченко и Андрей Каплей