Привет, меня зовут Павел Савельев, я руководитель отдела автоматизации бизнес-процессов в Lamoda. Мы работаем с очень разными задачами, и стараемся подобрать для каждой наиболее удобный инструментарий. Соответственно, мы используем разные языки — в наших системах можно встретить и Java, и Go, и немного Kotlin под андроид. При этом значительная часть разработки ведется на PHP, на нем написаны более двух десятков сервисов, которые автоматизируют не только работу с заказами, но и операционные процессы широкой сети доставки, колл-центров в трёх странах и собственной фотостудии, а также предоставление всего этого в виде услуг нашим B2B-партнерам. Эти сервисы поддерживают и развивают 5 команд разработки нашего отдела.

image

По мере развития как самих сервисов, так и инфраструктуры вокруг них, в этих системах все чаще возникают похожие задачи, такие как логирование в общую 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)


  1. smarthomeblog
    12.09.2019 15:28

    Если возможно, расскажите поподробнее про технические и бизнес-метрики Ваших микросервисов и как и чем они потом обрабатываются для генерации отчетов?


    1. pbatanov
      12.09.2019 16:24
      +1

      Технические метрики для микросервисов мы собираем глобально двух типов — инфраструктурные (la приложения, базы, состояние подов k8) и данные из работающего приложения (например длину очереди задач, внутренние счетчики ошибок\событий). Для бизнес метрик используем в основном данные из приложения — как пример мы чаще всего смотрим сколько времени занимают те или иные задачи в микросервисе (нам важны такие SLA, т.к. есть вполне конкретные юридические ограничения на время проведения некоторых финансовых операций).

      В проектах, написанных на PHP, помощью lamoda/metrics мы формируем отчеты либо в режиме on demand (т.е. пересчитываем каждый раз, когда скрейпер приходит забирать отчет), либо в фоновом режиме (тогда отдаем последний отчет скрейперу каждый раз).

      Отчеты формируем в родном формате prometheus (раньше использовали telegraf httpjson, поэтому в либе есть и этот формат).

      Дальше уже просто работаем с прометеусом как с источником данных в различных системах (grafana, icinga).

      Параллельно с этим используем (особенно для метрик связанных с фактами вида «что-то произошло») обычно логгирование


      1. smarthomeblog
        12.09.2019 16:40

        Спасибо большое!


  1. donpadlo
    12.09.2019 17:43

    Востребовано решение на PHP по работе с кассами АТОЛ которые не «в облаке — АТОЛ-онлайн», а которые на «столе», типа АТОЛ-55Ф и иже с ними. Многие у кого и магазин и сайт вынуждены 2 кассы держать, т.к. сайты на PHP, а работа с драйверами только на Python, С++ и на Андроиды. Костыли есть, но не многие «осиляторы»… В свое время пришлось городить транслятор вызовов из PHP в Pyhton ради того чтоб пофискализировать продажи с сайта…


    1. n0wheremany
      12.09.2019 18:08

      Доступ к принтеру АТОЛ можно получить через COM. Тем более в стандартном комплекте дров есть примеры, в том числе, на JS.
      Зачем что-то ещё?


      1. donpadlo
        13.09.2019 10:07

        Многие сайты на PHP делаются до сих пор. И логично имея бекенд на PHP, писать всё на нем, чтоб не делать вермишель


        1. n0wheremany
          13.09.2019 16:25

          Если у вас касса офф подключена к не к серверу, проще сделать через JS.
          Я делал через COM — приложение и касса были запущены на одном компе.
          Если вы каким то образом зацепитесь к кассе через СОМ от сервера — делайте на PHP.
          ewolf говорит, что есть свой веб-сервер кассы — пробуйте через него, на том же PHP.

          В общем сначала нужно читать доку.


    1. ewolf
      12.09.2019 21:47

      Мы держим АТОЛ в облаке для фискализации всех операций, которые происходят без физического участия сотрудников: онлайн платежи на сайте, возвраты и т.п. Это очень удобно именно для онлайн платежей и интернет магазинов, которые не осуществляют физические рассчеты на месте. Надеемся, что скоро станет законодательно возможно и оффлайн рассчеты тоже фискализировать через онлайн кассы.

      При этом работать с физической кассой также можно из PHP — в нем есть необходимые средства для реализации как бинарных протоколов, а АТОЛ вообще имеет встроенный в кассу веб-сервер.

      Однако, в нашем случае физические кассы — это кассы на пунктах выдачи товаров и у наших торговых представителей, распределенные по всем регионам России, которые не возможно просто так подключить к какому-то одному серверу. Поэтому для работы с ними мы не используем PHP напрямую, а используем наше же ПО для торговых представителей, которое представляет собой нативное Android приложение.