По мере развития как самих сервисов, так и инфраструктуры вокруг них, в этих системах все чаще возникают похожие задачи, такие как логирование в общую CLS (Centralized Logging System), тестирование файлового хранилища, сбор метрик для Prometheus и другие. Мы стараемся стандартизировать способы решения таких задач и использовать для разных систем общие компоненты.
Когда одна из команд сталкивается с адаптацией или интеграцией нового сервиса/инструмента, который может стать общим для всех, мы инициируем разработку библиотеки в этой команде. А впоследствии готовый компонент подготавливается для будущего переиспользования и выкладывается в общий доступ.
Так так такой процесс происходит у нас регулярно, мы составили гайдлайн, который позволяет провести его наиболее безболезненно — об этом я постараюсь сделать доклад на одной из ближайших конференций.
Более двух десятков наших PHP-библиотек мы выложили в публичный доступ на GitHub. И планируем выкладывать и дальше. Зачем? Ну, мы вложили много ресурсов и (хочется верить) сделали хорошо. И мы хитро надеемся, что другие разработчики будут использовать наши библиотеки, помогать их допиливать и развивать дальше, вместо того, чтобы тратить время на написание своих аналогов с нуля. В этой статье я хочу кратко рассказать про семь библиотек, разработанных для решения частых для e-commerce задач — я буду рад, если они пригодятся и вам, а еще больше обрадуюсь их совместному развитию :)
1. Онлайн-фискализация: клиент для АТОЛ Онлайн
Как и другие компании России, мы обязаны полностью соответствовать требованиям ФЗ-54, одним из которых является онлайн-фискализация. Все заказы, предоплачиваемые на сайте lamoda.ru, обязательно фискализируются: на них формируются онлайн-чеки, которые отправляются покупателям. Наш сервис фискализации работает по API с системой АТОЛ Онлайн, и первая в нашем списке библиотека — полноценный клиент для этого сервиса. Помимо самой библиотеки мы выложили также бандл, при помощи которого можно легко подключить ее к любым проектам на базе фреймворка Symfony. Сама же библиотека может быть встроена в любой другой PHP-фреймворк: Laravel, Yii и др. — достаточно написать лишь “обертку” для библиотеки.
2. Предоплатные платежи: взаимодействие с Payture
Для обработки предоплатных платежей мы активно взаимодействуем с сервисом Payture. У этого сервиса есть несколько программных интерфейсов. Мы используем вариант Payture InPay и написали собственный API-клиент для него. Библиотека позволяет манипулировать несколькими терминалами, поддерживает стандартное логирование PSR-3. Также есть возможность использовать преднастроенный клиент Guzzle — это позволяет легко организовать тестирование с помощью Guzzle Mock Handler.
Наш бандл к библиотеке предоставляет семантическую конфигурацию терминалов и позволяет удобно сконфигурировать настройки клиента (пока только таймауты) для разных операций по API.
3. Маркировка товаров: парсер кодов GS1 Datamatrix
Один из важнейших проектов 2019 года в нашей компании — поддержка государственной маркировки товаров. В рамках этого проекта на все товары определенных категорий будут наноситься специальные уникальные коды — в формате GS1 Datamatrix. Эти коды позволят любому покупателю проверить подлинность товаров, их происхождение и историю. Для того, чтобы внутренние системы Lamoda могли работать с этими штрихкодами, мы разработали библиотеку для правильного парсинга кодов GS1.
В ближайшее время мы также планируем выложить исходные коды разработанных нами клиентов для взаимодействия с Информационной Системой Маркировки и Прослеживаемости (ИС МП).
4. Управление микросервисами: middleware для шины команд Tactician
У нас есть более сотни микросервисов, которые выполняют множество отдельных операций: проверяют статусы платежей или новые файлы в хранилищах, отправляют управляющие команды в кассы, скачивают и обрабатывают фотографии с внешних сервисов. Практически все эти операции выполняются в фоновом режиме, и для управления ими отлично подходит паттерн шина команд. Для реализации шины в PHP-системах мы выбрали готовое решение — открытую библиотеку Tactician.
Однако, возникла проблема: наши фоновые команды часто взаимодействуют с внешними сервисами, которые имеют ограничение на количество операций в n секунд. А в Tactician отсутствует возможность управлять количеством исполняемых команд в определенное окно времени. Поэтому мы разработали дополнительный middleware — библиотеку Tactician rate limit. С ее помощью можно добавить новый слой обработки, который отслеживает количество выполняемых в шине команд согласно выбранной стратегии rate limiting. Стратегии подключаемы, из коробки доступны стратегии из библиотеки stiphle.
Также в открытом доступе есть наш Symfony bundle к библиотеке.
5. Сбор и рендеринг метрик для Prometheus
Наши микросервисы генерируют технические и бизнес-метрики, которые потом собираются через Prometheus Operator со всего кластера k8s. Для управления всем этим мы написали библиотеку, которая обрабатывает пользовательские метрики по сценарию «собери-сохрани-покажи». При этом библиотека поддерживает режимы работы, в которых можно опустить один из пунктов сценария, чтобы увеличить эффективность. Например, для быстрых вычислимых метрик может выполняться упрощенный сценарий «собери-покажи». А работа с медленными бизнес-метриками может частично переводиться в фон, при этом разбиваясь на два этапа: «собери-сохрани» + «собери (из хранилища) — покажи».
В библиотеке есть необходимые уровни абстракции как для написания своих генераторов метрик, так и для написания хранилищ. Из коробки есть абстрактный адаптер для Doctrine, который можно настроить на entity для сохранения данных в БД.
В качестве форматов рендера метрик в данный момент поддерживаются prometheus и telegraf httpjson.
В комплекте к библиотеке идет Symfony bundle, который предоставляет семантическую конфигурацию источников метрик, хранилищ и роутинга метрик. Также в нем есть команды-хелперы для отладки и сохранения метрик из источников (например, для расчета метрик по cron).
6. Тестирование файлового хранилища: работа с разными файловыми системами
Для автоматизации тестирования мы используем фреймворк Codeception, который позволяет нам писать тесты различных уровней и имеет достаточно обширную библиотеку стандартных модулей. Подробнее о наших подходах к разработке тестов мы писали недавно в отдельной статье и рассказывали на конференции PHP Russia. У Codeception есть готовые модули для взаимодействия с FTP и локальной файловой системой FileSystem, но в наших тестах есть потребность работы с бОльшим количеством файловых систем. Как минимум, мы используем еще AWS S3 и Webdav. Кроме того, со всеми файловыми системами хотелось бы взаимодействовать по одному API (это же всё файловые системы :)).
К счастью, существует открытая библиотека FlySystem, которая предоставляет единый программный интерфейс для работы с разными файловыми системами. Так что нам потребовалось только объединить два инструмента — что мы и сделали, написав обертку над FlySystem в виде модуля Codeception-flysystem. Сейчас он поддерживает SFTP, S3 и Webdav. Достаточно один раз сконфигурировать настройки для подключения к нужной файловой системе в yml-конфиге тестов, и после этого можно работать со всеми файловыми системами по одинаковому набору методов: записать файл, скопировать файл, почистить директорию и т.д. Модуль уже включён в страницу дополнений и рекомендаций от Codeception: codeception.com/addons.
7. Работа с переменными окружения в multi tenant режиме
В отделе автоматизации бизнес-процессов существуют системы, которые работают в режиме multi tenant (многоарендности). Для обеспечения их работы необходимо уметь работать с переменными окружения — определять, какую именно переменную использовать в текущий момент времени.
Наша библиотека предоставляет несколько стратегий для работы с переменными окружения в multi tenant режиме. Основываясь на параметрах, переданных на этапе инициализации, библиотека определяет, к какой именно переменной окружения следует обратиться в текущем запросе.
Продолжение следует
Это лишь первая часть библиотек. Внутри у нас есть ещё с десяток — они ждут очереди, когда мы их немного «причешем» и выложим в общий доступ. Меня мотивирует понимание, что эти библиотеки могут быть полезны кому-то ещё. Я радуюсь комментариям и звёздочкам на гитхабе, и надеюсь дальше развивать библиотеки вместе с другими разработчиками. Ведь с АТОЛ и Payture работают многие российские e-commerce проекты. Для Datamatrix, помимо описанного в статье парсера кодов, у нас есть еще пара клиентов, которые мы уже используем внутри — эти библиотеки первые в очереди на GitHub.
Стараемся не забывать и про остальные языки — мы уже выложили первую библиотеку на Go (про нее подробнее писали тут на Хабре) и готовим другие. Stay tuned!
Комментарии (8)
donpadlo
12.09.2019 17:43Востребовано решение на PHP по работе с кассами АТОЛ которые не «в облаке — АТОЛ-онлайн», а которые на «столе», типа АТОЛ-55Ф и иже с ними. Многие у кого и магазин и сайт вынуждены 2 кассы держать, т.к. сайты на PHP, а работа с драйверами только на Python, С++ и на Андроиды. Костыли есть, но не многие «осиляторы»… В свое время пришлось городить транслятор вызовов из PHP в Pyhton ради того чтоб пофискализировать продажи с сайта…
n0wheremany
12.09.2019 18:08Доступ к принтеру АТОЛ можно получить через COM. Тем более в стандартном комплекте дров есть примеры, в том числе, на JS.
Зачем что-то ещё?donpadlo
13.09.2019 10:07Многие сайты на PHP делаются до сих пор. И логично имея бекенд на PHP, писать всё на нем, чтоб не делать вермишель
n0wheremany
13.09.2019 16:25Если у вас касса офф подключена к не к серверу, проще сделать через JS.
Я делал через COM — приложение и касса были запущены на одном компе.
Если вы каким то образом зацепитесь к кассе через СОМ от сервера — делайте на PHP.
ewolf говорит, что есть свой веб-сервер кассы — пробуйте через него, на том же PHP.
В общем сначала нужно читать доку.
ewolf
12.09.2019 21:47Мы держим АТОЛ в облаке для фискализации всех операций, которые происходят без физического участия сотрудников: онлайн платежи на сайте, возвраты и т.п. Это очень удобно именно для онлайн платежей и интернет магазинов, которые не осуществляют физические рассчеты на месте. Надеемся, что скоро станет законодательно возможно и оффлайн рассчеты тоже фискализировать через онлайн кассы.
При этом работать с физической кассой также можно из PHP — в нем есть необходимые средства для реализации как бинарных протоколов, а АТОЛ вообще имеет встроенный в кассу веб-сервер.
Однако, в нашем случае физические кассы — это кассы на пунктах выдачи товаров и у наших торговых представителей, распределенные по всем регионам России, которые не возможно просто так подключить к какому-то одному серверу. Поэтому для работы с ними мы не используем PHP напрямую, а используем наше же ПО для торговых представителей, которое представляет собой нативное Android приложение.
smarthomeblog
Если возможно, расскажите поподробнее про технические и бизнес-метрики Ваших микросервисов и как и чем они потом обрабатываются для генерации отчетов?
pbatanov
Технические метрики для микросервисов мы собираем глобально двух типов — инфраструктурные (la приложения, базы, состояние подов k8) и данные из работающего приложения (например длину очереди задач, внутренние счетчики ошибок\событий). Для бизнес метрик используем в основном данные из приложения — как пример мы чаще всего смотрим сколько времени занимают те или иные задачи в микросервисе (нам важны такие SLA, т.к. есть вполне конкретные юридические ограничения на время проведения некоторых финансовых операций).
В проектах, написанных на PHP, помощью lamoda/metrics мы формируем отчеты либо в режиме on demand (т.е. пересчитываем каждый раз, когда скрейпер приходит забирать отчет), либо в фоновом режиме (тогда отдаем последний отчет скрейперу каждый раз).
Отчеты формируем в родном формате prometheus (раньше использовали telegraf httpjson, поэтому в либе есть и этот формат).
Дальше уже просто работаем с прометеусом как с источником данных в различных системах (grafana, icinga).
Параллельно с этим используем (особенно для метрик связанных с фактами вида «что-то произошло») обычно логгирование
smarthomeblog
Спасибо большое!