Repository: redis/redis-py
File: redis/asyncio/connection.py (Python)

Code before:
            connection = self.get_available_connection()

        # We now perform the connection check outside of the lock.
        try:
            await self.ensure_connection(connection)
            return connection
        except BaseException:
            await self.release(connection)
            raise

    def get_available_connection(self):
        """Get a connection from the pool, without making sure it is connected"""
        try:
            connection = self._available_connections.pop()
        except IndexError:
            if len(self._in_use_connections) >= self.max_connections:
                raise MaxConnectionsError("Too many connections") from None
            connection = self.make_connection()
        self._in_use_connections.add(connection)
        return connection

    def get_encoder(self):
        """Return an encoder based on encoding settings"""
        kwargs = self.connection_kwargs
        return self.encoder_class(
            encoding=kwargs.get("encoding", "utf-8"),
            encoding_errors=kwargs.get("encoding_errors", "strict"),
            decode_responses=kwargs.get("decode_responses", False),
        )

    def make_connection(self):
        """Create a new connection.  Can be overridden by child classes."""
        return self.connection_class(**self.connection_kwargs)

    async def ensure_connection(self, connection: AbstractConnection):
        """Ensure that the connection object is connected and valid"""
        await connection.connect()
        # connections that the pool provides should be ready to send
        # a command. if not, the connection was either returned to the
        # pool before all data has been read or the socket has been
        # closed. either way, reconnect and verify everything is good.
        try:
            if await connection.can_read_destructive():
                raise ConnectionError("Connection has data") from None
        except (ConnectionError, TimeoutError, OSError):
            await connection.disconnect()
            await connection.connect()
            if await connection.can_read_destructive():
                raise ConnectionError("Connection not ready") from None

    async def release(self, connection: AbstractConnection):

Review comment (refactor):
The timing measurement for connection creation is inaccurate compared to the synchronous version. The timer `start_time_created` is started before calling `get_available_connection()`, which means it includes:
1. Time to calculate connection counts (2 len() calls)
2. Time to pop from the available list (for existing connections) or create a new one
3. Time to calculate connection counts again and determine if created
4. Time spent while holding the lock

In the synchronous version (redis/connection.py:2953), the timer only starts when entering the except IndexError block, meaning it only starts when we know for certain a connection is being created. This should be refactored to only start the timer when a new connection is actually being created, similar to the sync version.

Consider moving the timer start to immediately before or after calling `make_connection()` inside `get_available_connection()`, or restructure to only start timing when `is_created` will be True.

Code after:
        reason="Use get_connection() without args instead",
        version="5.3.0",
    )
    async def get_connection(self, command_name=None, *keys, **options):
        """Get a connected connection from the pool"""
        # Track connection count before to detect if a new connection is created
        async with self._lock:
            connections_before = len(self._available_connections) + len(
                self._in_use_connections
            )
            start_time_created = time.monotonic()
            connection = self.get_available_connection()
            connections_after = len(self._available_connections) + len(
                self._in_use_connections
            )
            is_created = connections_after > connections_before

        # We now perform the connection check outside of the lock.
        try:
            await self.ensure_connection(connection)

            if is_created:
                await record_connection_create_time(
                    connection_pool=self,
                    duration_seconds=time.monotonic() - start_time_created,
                )

            return connection
        except BaseException:
            await self.release(connection)
            raise

    def get_available_connection(self):
        """Get a connection from the pool, without making sure it is connected"""
        try:
            connection = self._available_connections.pop()
        except IndexError:
            if len(self._in_use_connections) >= self.max_connections:
                raise MaxConnectionsError("Too many connections") from None
            connection = self.make_connection()
        self._in_use_connections.add(connection)
        return connection

    def get_encoder(self):
        """Return an encoder based on encoding settings"""
        kwargs = self.connection_kwargs
        return self.encoder_class(
            encoding=kwargs.get("encoding", "utf-8"),
            encoding_errors=kwargs.get("encoding_errors", "strict"),
            decode_responses=kwargs.get("decode_responses", False),
        )