Как я могу обернуть coroutine.__await__()?

Я хочу регистрировать каждый запрос на получение/выпуск в пуле asyncpg. Для этой цели я написал следующее

class CntPoolLogger:
    def __init__(self) -> None:
        self.conn_cnt = 0
        self.event_cnt = 0
        self.log_filename = "pool_usage.log"
        self.file = open(self.log_filename, "a")
    
    def log(self, event: str) -> None:
        self.file.write(f"{self.event_cnt},{event},{self.conn_cnt}\n")
        self.file.flush()

    def acquire(self) -> None:
        self.event_cnt += 1
        self.conn_cnt += 1
        self.log("acquire")

    def release(self) -> None:
        self.event_cnt += 1
        self.conn_cnt -= 1
        self.log("release")
    
    def __del__(self):
        self.file.close()


class LoggingPoolAcquireContext:
    def __init__(self, pool_acquire_context: asyncpg.pool.PoolAcquireContext, cnt_logger: CntPoolLogger):
        self.pool_acquire_context = pool_acquire_context
        self.cnt_logger = cnt_logger

    async def __aenter__(self, *args, **kwargs):
        res = await self.pool_acquire_context.__aenter__(*args, **kwargs)
        self.cnt_logger.acquire()
        return res

    async def __aexit__(self, *args, **kwargs):
        await self.pool_acquire_context.__aexit__(*args, **kwargs)
        self.cnt_logger.release()
    
    def awaitable_wraper(self, awaitable):
        ??????

    def __await__(self, *args, **kwargs):
        self.cnt_logger.acquire()
        return self.pool_acquire_context.__await__(*args, **kwargs)
        
        

class LoggingAsyncPGPool:
    def __init__(self, pool, cnt_logger: CntPoolLogger):
        self._pool = pool
        self.cnt_logger = cnt_logger

    def acquire(self, *args, **kwargs):
        res = LoggingPoolAcquireContext(self._pool.acquire(*args, **kwargs), cnt_logger=self.cnt_logger)
        return res

    async def release(self, *args, **kwargs):
        await self._pool.release(*args, **kwargs)
        self.cnt_logger.release()
    
    async def close(self, *args, **kwargs):
        await self._pool.close()

Я хочу, чтобы счетчик обновлялся только после того, как соединение было фактически установлено/освобождено. Поэтому я обновляю счетчик только после операторов ожидания. Однако в этом методе

def __await__(self, *args, **kwargs):
        self.cnt_logger.acquire()
        return self.pool_acquire_context.__await__(*args, **kwargs)

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

Мой вопрос: есть ли способ как-то обернуть

self.pool_acquire_context.__await__(*args, **kwargs)

То есть, когда мы ожидаем его где-то в будущем, он обновляет счетчик только после установления соединения?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
67
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как вы обнаружили, __await__ должен вернуть генератор. Итак, напишите одно:

def __await__(self, *args, **kwargs):
    self.cnt_logger.acquire()
    try:
        return yield from self.pool_acquire_context.__await__(*args, **kwargs)
    finally:
        self.cnt_logger.release()

Другие вопросы по теме

Похожие вопросы