Thanks to visit codestin.com
Credit goes to github.com

Skip to content

ivanwolodin/iohttp_server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Общее описание

Микросервис, использующий httpio. Задействует несколько потоков. Используется python 3.7

  • В одном потоке асинхронно сервер получает данные о курсе доллара, рубля и евро
  • В другом потоке сервер асинхронно отвечает на HTTP запросы на порту 8080. Реализовано REST API (см. документацию)

Документация

REST API, отвечает на запросы следующего вида (тип запроса, url, payload //комментарий):

  • GET /usd/get
  • GET /rub/get
  • GET /eur/get
  • POST /amount/set {"usd":10}
  • POST /amount/set {"rub":100.5, "eur":10, "usd":20}
  • POST /modify {"usd":5} // добавить к текущему количеству usd 5
  • POST /modify {"eur":10, "rub":-20} // добавить к текущему количеству eur 10, уменьшить текущее количество rub на 20
  • GET /reverse_console_output_status // изменяет значения флага debug для вывода данных в консоль/лог
  • GET /amount/get отвечает общей суммой средств для каждой из трёх валют с учётом текущего курса, количеством каждой из валют отдельно и текущим курсом.
    • пример ответа: {"rub-usd": 68.6319, "rub-eur": 77.9658, "usd-eur": 1.14, "rub": 0, "usd": 0, "eur": 0, "sum": "0.0 rub / 0.0 usd / 0.0 eur"}
  • На остальные запросы в случае успеха возвращается {'result': True}

Реализация приложения

Микросервис реализован на трендовом стеке - asyncio, httpio.

Приложение состоит из модуля с абстрактным классом и второго модуля, импортирующего этот класс.

Абстрактный класс AbstractCurrencyHandler.

Класс для работы приложения CurrencyHandler

Логирование - это отдельная сущность, поэтому она вынесена в отдельный модуль logger.py

Интеграционные тесты находятся в модуле tests.py. Запускаются следующим образом: pytest -v tests.py

Логирование

Логирование осуществляется через стандартный модуль logging. Аттрибуты определены в классе AbstractCurrencyHandler:

Формат лога: '%(asctime)s — %(name)s — %(levelname)s — %(message)s')

Вид лога:

2020-06-05 17:46:41,055 — currency_handler.log — DEBUG — Initial amount: {'USD': 0, 'EUR': 0, 'RUB': 0}

2020-06-05 17:46:41,055 — currency_handler.log — INFO — Server Started

2020-06-05 17:47:46,171 — currency_handler.log — INFO — USD has changed to 68.6319 EUR has changed to 77.9658

  • _log_events() используется для занесения информации в лог-файл currency_handler.log
  • _console_output() выводит данные в консоль
  • _hook_currency_values_changed() выводит информацию в консоль и в лог файл, если изменилась стомость валюты

Запуск приложения

Запуск приложения возможен с аргументами командной строки.

Можно задать 5 аргументов:

  • --eur - количество евро (по-умолчанию 0)
  • --rub - количество рублей (по-умолчанию 0)
  • --usd - количество долларов (по-умолчанию 0)
  • --period - частота в секундах опроса удаленного сервера с данными о курсах валют (по-умолчанию 5 )
  • --debug - режим дебага (по-умолчанию False). Возможные значения для перевода в True:
    • 1, True, true, y, Y

В случае, если debug не передается, вся информация о запросах сервера записывается в лог файл.

Если задается не falsy значение параметра debug, то данные о запросах удаленного информационного сервера печатаются в консоль, а также данные POST-запросов к серверу выводятся в консоль.

Можно изменить поведение приложение вызвав API /reverse_console_output_status

Для анализа и парсинга аргументов командной строки используется модуль argparse

Примеры запуска приложения из командной строки:

python currency_handler.py --eur 10 --usd 5 --rub 100 --period 5 --debug true

python currency_handler.py --eur 10 --debug true

python currency_handler.py --eur 10

python currency_handler.py

Возможные улучшения

  • В данный момент для логгирования и вывода данных при дебаге используется три сущности. Можно изменить это поведение добавив Handler для консоли, т.е. реализовав внутри класса Logger функцию get_file_handler() и использовать этот обработчик: self.logger.addHandler(Logger._get_file_handler())

  • Традиционная проблема при работе с asyncio и потоками - задача graceful shutdown, в данный момент этого нет. При попытке с помощью ctrl+c прервать работу приложения не останавливается event-loop и запущенный поток. Проблема усугубляется тем, что в потоке запущен отдельный event-loop. Event-loop, который запрашивает курсы валют можно остановить так:

    try:
        loop.run_until_complete()
    except KeyboardInterrupt as e:
        print("Caught keyboard interrupt. Graceful shutdown...")
    finally:
        loop.close()

при этом вероятна ошибка asyncio cannot close a running event loop, потому что после запуска начнутся сетевые I/O операции.

Непонятно, как при этом быть с запущенным потоком. Можно было бы создать собственный класс, унаследованный от Thread традиционным образом и переопределить метод run(), но внутри запущен loop..

  • Внутри класса CurrencyHandler корутина fetch_currency запрашивает данные у информационного сервера с курсами валют. Нужно добавить несколько попыток запроса, ограниченные значением max_retries, в том случае, если запросы падают и удаленный сервер не отдает данные.

Примечание

Приложение написано с огромным уважением к PEP8, но кое-где не соблюдается максимальная длина строк. Впрочем, внутри стандартных модулей Python есть стилистические нарушения значительно серьезнее..

Как написано в самом первоисточнике "sometimes style guide recommendations just aren't applicable. When in doubt, use your best judgment".

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages