Опыт использования контекстных менеджеров в микросервисах
Что проверяют
Понимаете ли вы, что with это не сахар для закрытия файла, а гарантия освобождения ресурса при любом выходе из блока, включая исключение. И умеете ли писать свои менеджеры, в том числе асинхронные: в сервисе это соединения, транзакции, блокировки и замеры.
Как отвечать
Дайте определение через протокол __enter__ и __exit__, упомяните contextlib.contextmanager как короткую форму через генератор. Затем переведите разговор на сервисную практику: соединение берётся из пула, а не создаётся заново, транзакция оформляется отдельным менеджером.
from contextlib import asynccontextmanager
@asynccontextmanager
async def transaction(pool):
async with pool.acquire() as conn:
async with conn.transaction():
yield connДальше назовите то, что отличает опытного кандидата: __aenter__ и __aexit__ для асинхронных клиентов, AsyncExitStack, когда набор ресурсов известен только в рантайме, lifespan приложения как тот же протокол на уровне процесса, и нересурсные применения: замер длительности блока с отправкой метрики, временная подмена настроек в тестах, распределённая блокировка.
Где спотыкаются
Открывают соединение внутри __enter__ на каждый запрос вместо того, чтобы брать его из пула. Под нагрузкой сервис упирается в лимит соединений базы, а задержка каждого запроса растёт на установке соединения.
Второе: не знают, что истинное значение, возвращённое из __exit__, подавляет исключение. Случайный return True превращает ошибки в тишину, и потерянные транзакции ищут потом неделями.
Третье: путают синхронный и асинхронный протоколы. Обычный with на асинхронном клиенте падает, а синхронное закрытие внутри асинхронного кода блокирует цикл событий, и весь сервис встаёт из-за одной строки.