Вам предлагается задача на умение писать и отлаживать цепочные преобразование данных (pipeline вычисления)
Одну из наших систем можно описать как pipeline, где идет преобразование одного JSON в другой.
От соискателя мы желаем увидеть понимание построение и отладки таких решений - написать такой pipeline в миниатюре, а потом описать способ отладки.
Написать пример цепочного вычисления (Шаг 1), а затем показать как его можно отлаживать (Шаг 2).
Вам необходимо написать 2 примитивных сервиса на Fast API, которые реализуют PING PONG.
- Сервисы по POST принимают JSON с словарем.
- Сервис А добавляет в ключ "digits" случайное целое число (с 0 до 100)
- Сервис B считает на основе массива “digits” среднее, максимум и минимум и кладет в ключи avg, max, min.
- Сервисы кидают по очереди кидают запросы друг в друга, пока
Получается PING PONG, где в словарь постепенно добавляются значения. - Каждый сервис имеет валидацию данных.
Для эмуляции валидации, предлагаем при обработке запроса выдавать 400 ошибку, если случайное число от 0 до 10 делится на 3. - PING PONG заканчивается, когда один из сервисов отдает 400-ую ошибку
- Предложите варианты отладки pipeline, который написали на шаге 1:
- Когда есть доступ до кода (разработчику)
- Когда нет доступа до кода (QA)
Примечание: Основная цель отладке, понять в какой момент прервался pipeline и state на этот момент.
- Какую дополнительную мета-информацию стоит добавить, чтобы упростить отладку?
В результате тестового задания ожидается:
- Ссылка на gitlab/github репозиторий с реализацией pipeline.
Рекомендуем писать код с расчетом запуска в Docker контейнерах. - В репозитории должен лежать README.md файл с описанием подхода к отладке.
Не получил ответа на уточнения в требованиях. Изменил реализацию, исходя из здравого смысла:
- Сервис B отправляет в сервис A массив digits.
- В условии про валидацию данных используется последнее число из массива digits.
- При ошибке валидации возвращается не 400, а 422 ошибка
make up
curl -i -X POST "http://127.0.0.1:5001/ping" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"digits\":[42]}"
make logs
Запуск автотестов
make tests
Запуск статического анализа кода
make static_check
Подключение дебаггера
cp docker-compose.override.yml.template docker-compose.override.yml
# insert 'import pdb; pdb.set_trace()' in code
make up
make attach SERVICE=service_a
Настройка хот-релода кода:
cp docker-compose.override.yml.template docker-compose.override.yml
make up
make restart
Перезапуск:
make down
make up
Автоформатирование (black):
make format
Swagger для сервиса A: http://127.0.0.1:5001/docs
Swagger для сервиса B: http://127.0.0.1:5002/docs
Просмотр логов:
make logs
# одного сервиса
make logs SERVICE=service_a
Настройка логов: файл logging_config.json
В ответе на HTTP-запросы к сервисам возвращается заголовок X-Correlation-Id
.
У цепочки запросов будет один X-Correlation-Id
.
Если заголовок не передан, то сервис сгенерирует его.
Желательно настроить в системе аггрегации логов фильтр по X-Correlation-Id
.
В Swagger есть возможность передавать заголовок X-Correlation-Id
.
Логгируются запросы и ответы, получаемые и отправляемые сервисами.
Получить последние 10 ответов сервиса B по X-Correlation-Id
:
curl -X GET "http://127.0.0.1:5001/service_b_responses/{X-Correlation-Id}" -H "accept: application/json"
Получить последние 10 ответов сервиса A по X-Correlation-Id
:
curl -X GET "http://127.0.0.1:5002/service_a_responses/{X-Correlation-Id}" -H "accept: application/json"
-
Если необходимо выполнять более сложные вычисления в сервисе B, то можно переиспользовать предыдущий шаг вычислений.
Для этого можно считать некриптографический хэш от полученных digits (например, xxhash). Расчитанные значения положить в хэш-мэп. На следущем шаге попробовать получить предыдущие расчитанные значения, применив хэш-функцию к массиву digits без последнего элемента. -
Объединить Swagger-документации двух сервисов в одну. Улучшить описание.
-
Добавить отправку в Sentry необработанных ошибок.
-
Если необходимо горизонтальное масштабирование, то необходимо:
либо хранить историю запросов в общем хранилище (например, редис),
либо реализовать фасад перед сервисами, который собирает историю из разных инстансов,
либо отказаться от дополнительной функциональности по отдаче истории.