добавить graceful shutdown для пула
на текущий момент при закрытии пула мы закрываем все его соединения, в том числе внутри `_used`, то есть используемые в моменте:
async def close(self) -> None:
"""
Closes all connections in the pool.
Note:
This should be called during application shutdown to clean up resources.
"""
if self._topology_tracker is not None:
await self._topology_tracker.stop()
await self._query_metadata_service.close()
async with self._lock:
total = len(self._pool) + len(self._used)
while self._pool:
conn = self._pool.popleft()
try:
await conn.close()
except Exception as e:
logger.warning("Pool close: could not close connection: %s", e)
for conn in self._used:
try:
await conn.close()
except Exception as e:
logger.warning("Pool close: could not close connection: %s", e)
self._used.clear()
logger.info("Pool closed (%d connection(s))", total)
предлагается добавить `timeout` в pool.close() и закрывать используемые соединения аккуратно:
- пометить используемые соединения на закрытие (for conn in pool._used set to_evict = True) (в рамках задачи #68 (closed) было добавлено отложенное удаление)
- закрыть все неиспользуемые соединения (conn in pool._pool)
- ждать и проверять _used вплоть до таймаута (тут мы ждем пока _used будут зарелижены и закрыты за счет твоего механизма), возможно timeout минус какое-то время
и в конце есть варианты обработки:
- если за таймаут не удалось закрыть, то выдавать ошибку закрытия (тогда не будет идемпотентности у закрытия, но зато не будут обрываться ошибками запросы на используемых соединениях)
- или по истечению таймаута форсировать закрытие все равно
в asyncpg есть похожие механизмы. в рамках задачи необходимо их изучить, возможно почерпнуть еще полезный вариант
Edited by Asya Lomakina