Filyushin
@Filyushin
Python, Delphi, Firebird

Как спроектировать python приложению, реализующее консьюмера RabbitMQ и требующего HealthCheck?

Разрабатываем приложение на Python, которое слушает очередь (принимает сообщения и выполняет работу над ним). Требования devopsов: наличие healthcheck у приложения. Healthcheck действительный, то есть отдаём значение 200, если приложение и инфраструктура доступны.

Healthcheck планируем делать на FastAPI/aiohttp в виде одного ендпоинта с отдачей статуса.

Вопрос: насколько верно делать class Application(Object) с консьюмерами плюс добавить внутрь приложения запуск FastAPI instance с запуском через uvicorn?
Не будет ли проблем с event loop при переключении между обработкой сообщений RabbitMQ и FastAPI проверкой healthcheck?

Нечто подобное:

class HTTPServerManager:
    settings: Settings
    api_server: Optional[Server] = None
    additional_router: Optional[APIRouter] = None
    live_probe_service: LiveProbeService = None

    LOGGING_EXCLUDE_ENDPOINT = ['/metrics', '/docs', '/health/live', '/openapi.json', ]

    def __post_init__(self):
        self.port = self.settings.app_http_server_port
        self.http_handler = self.settings.app_http_server_handler
        self.dev_mode = self.settings.dev_mode
        self.loop = asyncio.get_event_loop()
        self.server_application = ServerApplication(self.settings, self.live_probe_service)
        self.init_api_server()

    async def run_startup(self) -> None:
        self.init_api_server()

    async def run_shutdown(self) -> None:
        if self.api_server is not None and self.api_server.started:
            await self.api_server.shutdown()

    async def serve(self) -> None:
        await self.api_server.serve()

    def init_api_server(self) -> None:
        if self.additional_router:
            self.server_application.include_router(self.additional_router)
        config = Config(
            app=self.server_application,
            loop=self.http_handler,
            host='0.0.0.0',
            port=self.port,
            log_config=get_uvicorn_config(HTTPServerManager.LOGGING_EXCLUDE_ENDPOINT),
            access_log=True,
        )
        self.api_server = Server(config)


Базовое приложение:

class Application(BaseApplication):
    def __init__(self) -> None:
        self.container_manager = ContainerManager(self.container_cls)
        self.container = self.container_manager.get_container()
       ...
        self.loop = asyncio.get_event_loop()
        self.http_transport = self.container.get(HTTPServerManager)
        self.live_probe_service = self.container.get(LiveProbeService)


    def run(self) -> None:
        try:
            self.logger.info(f'Application {self.app_name} is starting')
            self.loop.run_until_complete(self.container_manager.run_startup())
            self.logger.info('Application container created')

            gather_tasks = asyncio.gather(
                self.queue_transport.run(),
                self.http_transport.serve(),
            )
            self.loop.run_until_complete(gather_tasks)
            self.loop.run_forever()
        except:
            ...
  • Вопрос задан
  • 312 просмотров
Пригласить эксперта
Ответы на вопрос 1
У приложения потребителя очереди должен иметься менеджер соединения с RabbitMQ. Как только соединение было установлено, запускается поток с веб-сервером и health-check. У потребителя очереди - основой поток, у веб-сервера - дочерний. Каждый работает независимо друг от друга. Для менеджера соединения с RabbitMQ может использоваться функция обратного вызова в библиотеке.
Таким образом, при вызове /health (или /health/live) всегда возвращается статус 200.
При внезапном разрыве соединения с RabbitMQ менеджер соединения приложения штатным образом пытается восстановить соединение (скажем, до N раз каждую секунду) и если облом, то выходим из приложения с ненулевым статусом (допустим, 1). Если приложение падает, то вместе с ним и health-check, что вызовет триггер по перезапуску приложения у процесса, который ведет мониторинг приложения.
Мониторинг самого RabbitMQ обычно ведется отдельными от приложения средствами. RabbitMQ может запускаться как on premises, так и в SaaS (допустим, CloudAMQP).
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы