{"id":19225827,"url":"https://github.com/mementomorri/micro_octo_handler","last_synced_at":"2026-05-03T17:33:27.250Z","repository":{"id":228662487,"uuid":"774583077","full_name":"mementomorri/micro_octo_handler","owner":"mementomorri","description":"Микросевисное приложение обработки сообщений на основе архитектуры REST.","archived":false,"fork":false,"pushed_at":"2024-04-03T12:49:13.000Z","size":2192,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-19T00:04:35.469Z","etag":null,"topics":["fastapi","fastapi-users","jwt","microservice","python","rest","sqlite"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mementomorri.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-03-19T20:00:33.000Z","updated_at":"2024-03-24T22:00:53.000Z","dependencies_parsed_at":"2024-03-22T14:54:07.662Z","dependency_job_id":"f12c8dac-47d8-4fc4-8a08-74207b55a3ef","html_url":"https://github.com/mementomorri/micro_octo_handler","commit_stats":null,"previous_names":["mementomorri/micro_octo_handler"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mementomorri/micro_octo_handler","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mementomorri%2Fmicro_octo_handler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mementomorri%2Fmicro_octo_handler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mementomorri%2Fmicro_octo_handler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mementomorri%2Fmicro_octo_handler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mementomorri","download_url":"https://codeload.github.com/mementomorri/micro_octo_handler/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mementomorri%2Fmicro_octo_handler/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32578648,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T06:36:36.687Z","status":"ssl_error","status_checked_at":"2026-05-03T06:36:09.306Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fastapi","fastapi-users","jwt","microservice","python","rest","sqlite"],"created_at":"2024-11-09T15:16:33.295Z","updated_at":"2026-05-03T17:33:27.233Z","avatar_url":"https://github.com/mementomorri.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# micro_octo_handler\nМикросевисное приложение обработки сообщений на основе архитектуры REST.  \n## Дословная формулировка т/з  \nРеализовать приложение, принимающее запросы на обработку через REST.\nСообщения обрабатываются двумя провайдерами:  \n - бесплатным\n - и платным,\n   \n путем общения через REST.  \nПо бесплатному провайдеру есть ограничение: он может принять какое-то количество запросов, затем блокирует обращения на определённый промежуток времени.  \nВозможно получить отказ в обслуживании формированием рабочего запроса на бесплатный сервис, однако правильнее обрабатывать количество отправленных запросов в сервис и сравнивать с доступным количеством.  \nПри блокировке запросы следует отправлять в платный сервис. При доступности бесплатного сервиса следует переключиться на бесплатный, минимизируя использование платного провайдера.\nПри разработке иметь в виду, что приложение может работать на нескольких изолированных подах без использования общей памяти.  \nНеобходимо наличие тестов.\n\n## Интуиция\n1. Поскольку подразумивается, что приложение может быть разделено на несколько подов, то имеет смысл реализовать микросервисную архитектуру. Приложение будет разделено на три микросервиса: \n    - бесплатный провайдер;  \n    - платный провайдер;\n    - аутентификация пользователей.\n2. По-умолчанию буду направлять клиента на бесплатный провайдер, если пороговое значение запросов превышено, то клиент будет перенаправлен на платный провайдер. Для имитации работы платного провайдера условно ограничу его использование по ключевому аттрибуту JWT токене.  \n3. Необходимо каким-то образом идентифицировать пользователя, поэтому добавлю идентификаю пользователя по стратегии JWT хранимых в куки файлах и изолирую пользователя от платного провайдера, если у него нет права доступа.\n4. Наличие БД не является необходимым, поскольку по заданию не уточняется нужно ли хранить информацию об обработанных сообщениях и нужно ли её кэшировать. Обработка сообщений в провайдерах будет имитироваться через обработку переданной строки сообщения.\n\n## Реализация\nРеализовано два провайдера обработки сообщений `free_provider` для бесплатной обработки сообщений и `paid_provider` для платной соответственно. Также добавлен микросервис для аутентификации пользователей и обработки информации связанной с ними `user_microservice`. Перед обработкой сообщения пользователь направляется на микросервис аутентификации, получает JWT токен и получает доступ к провайдеру обработки сообщений. При поверхностном тестировании обработка сообщений и переключение между провайдерами работает корректно. Проверить это можно в ручную собрав `venv` через соответствующие файлы зависимостей в папке `requierements` или через сборку контейнера используя `Dockerfile` в соответствующих папках провайдеров и микросервиса аутентификации пользователей.\n\n## Сборка и запуск\n### Контейнеры\nМожно сэимитировать разделение микросервисов на поды собрав каждый в отдельный докер контейнер. В папках `src/user_microservice`, `src/free_provider` и `src/paid_provider` имеются инструкции Dockerfile для сборки контейнера. Их можно собрать с помощью команд в комментариях к Dockerfile, а именно:\n- `src/user_microservice/Dockerfile` - собираем и запускаем командой: ```docker build . --tag users_microservice \u0026\u0026 docker run -p 8000:8000 users_microservice```;\n- `src/free_provider` - собираем и запускаем командой: ```docker build . --tag free_provider \u0026\u0026 docker run -p 2197:2197 free_provider```;\n- `src/user_microservice/Dockerfile` - собираем и запускаем командой: ```docker build . --tag paid_provider \u0026\u0026 docker run -p 2198:2198 paid_provider```.\n\nКаждый микросервис будет имееть соответствущий адес:\n- http://0.0.0.0:8000 для микросервиса пользователей;\n- http://0.0.0.0:2197 для бесплатного провайдера;\n- http://0.0.0.0:2198 для платного провайдера.\n\nТакже можно заглянуть в сгенерированную документацию в разделе `/docs` каждого микросервиса.\n\n### venv\n1. Для быстрой сборки и запуска приложения в режиме отладки можно воспользоваться скриптом `build_and_deploy.sh`. \n2. Либо собрать зависимости в ручную через файл зависимостей `dev.txt` из папки `requierements`, инициализировать виртуальную среду командой:\n```shell\ncd requirements; python -m venv venv; source venv/bin/activate; pip install -r dev.txt\n```\nи запустить сервисы через `uvicorn` из каждой папки, например `uvicorn microservice:app --reload --port=8000`\n## Ручное тестирование\nСымитируем поведение пользователя взаимодействующего в нашим приложением через API. Сначала пользователю необходимо зарегистрироваться, при регистрации укажем выиышленную почту и пароль для пользователя:  \n![Скриншот 1 - Регистрация](https://github.com/mementomorri/micro_octo_handler/blob/main/screenshots/Screenshot_1.png)  \nПосле регистрации наш тестовый пользователь bob получит ответ в виде статус кода 201 и в ответ получит добавленные о нем данные.  \n![Скриншот 2 - Ответ на регистрацию](https://github.com/mementomorri/micro_octo_handler/blob/main/screenshots/Screenshot_3.png)  \nДалее пользователю необходимо залогиниться, укажем электронную почту и пароль введенные при регистрации.  \n![Скриншот 3 - Авторизация](https://github.com/mementomorri/micro_octo_handler/blob/main/screenshots/Screenshot_4.png)  \nЕсли всё прошло успешно, пользователь получит статус код 204.  \n![Скриншот 4 - Ответ на авторизацию](https://github.com/mementomorri/micro_octo_handler/blob/main/screenshots/Screenshot_5.png)  \nИ JWT токен в виде куки.  \n![Скриншот 5 - JWT токен в куки](https://github.com/mementomorri/micro_octo_handler/blob/main/screenshots/Screenshot_6.png)  \nТеперь пользователь хочет воспользоваться бесплатным провайдером обработки сообщений, перейдем на адрес с бесплатным провайдером, введем значение токена и обрабатываемое сообщение.  \n![Скриншот 6 - Обработка бесплатным провайдером](https://github.com/mementomorri/micro_octo_handler/blob/main/screenshots/Screenshot_7.png)  \nВ ответ пользователь получит статус код 200 и результат обработки запроса. В тестовом варианте это просто перевернутая строка.  \n![Скриншот 7 - Результат обработки бесплатным провайдером](https://github.com/mementomorri/micro_octo_handler/blob/main/screenshots/Screenshot_8.png)  \nТеперь сыметируем ситуацию, когда пользователь отправил ещё 9 сообщений и лимит бесплатных сообщений для него закончился `\"free_messages_left\": 0`.  \n![Скриншот 8 - Результат обработки бесплатным провайдером](https://github.com/mementomorri/micro_octo_handler/blob/main/screenshots/Screenshot_9.png)  \nТеперь наш пользователь, не имея доступа к платному провайдеру, хочет обработать ещё одно сообщение, обращается к бесплатному провайдеру и получает такой ответ со статус кодом 403.  \n![Скриншот 9 - Обработки в отсутствии бесплатных сообщений](https://github.com/mementomorri/micro_octo_handler/blob/main/screenshots/Screenshot_11.png)  \nПредставим, что наш пользователь приобрел платную подписку и теперь его поле `paid_access` имеет значение `true`, снова обратившись к бесплатному провайдеру он увидит сообщение.  \n![Скриншот 10 - Получение платной подписки](https://github.com/mementomorri/micro_octo_handler/blob/main/screenshots/Screenshot_14.png)  \nТеперь сымитируем ситуацию, когда пользователь зарегистрировался днём ранее и исчерпал запас песплатных сообщений, обращайте внимание на дату в поле `refresh_at` - 25.03 и тукущую дату - 26.03.  \n![Скриншот 11 - обновление бесплатных сообщений](https://github.com/mementomorri/micro_octo_handler/blob/main/screenshots/Screenshot_15.png)  \nПользователь хочет обратиться к бесплатному провайдеру и видит успешный результат.  \n![Скриншот 12 - Обработка счетчика бесплатных сообщений](https://github.com/mementomorri/micro_octo_handler/blob/main/screenshots/Screenshot_16.png)  \nЕсли взглянуть в данные о пользователе, то видно, что дата следующей выдачи бесплатных сообщение и количество бесплатных сообщение обновилось.  \n![Скриншот 12 - Обновление поля бесплатных сообщений](https://github.com/mementomorri/micro_octo_handler/blob/main/screenshots/Screenshot_17.png)  \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmementomorri%2Fmicro_octo_handler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmementomorri%2Fmicro_octo_handler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmementomorri%2Fmicro_octo_handler/lists"}