Repository: aio-libs-abandoned/aioredis-py

Issue:
Support client name part of Pool & Connection
I'd like to set in my application a client name for my connections. This is supported via the commands, but when using the Pool/Connection object it sometimes reconnect/creates new connections hence losing the set name.
This feature also exists in py-redis and makes a lot of sense - you set it once in the initialization of the Pool/Connection and it sets it after connecting.

PR incoming


Discussion:

Resolving patch:
diff --git a/aioredis/commands/__init__.py b/aioredis/commands/__init__.py
--- a/aioredis/commands/__init__.py
+++ b/aioredis/commands/__init__.py
@@ -178,7 +178,8 @@ async def create_redis(
     parser=None,
     timeout=None,
     connection_cls=None,
-    loop=None
+    loop=None,
+    name=None
 ):
     """Creates high-level Redis interface.
 
@@ -194,6 +195,7 @@ async def create_redis(
         timeout=timeout,
         connection_cls=connection_cls,
         loop=loop,
+        name=name
     )
     return commands_factory(conn)
 
@@ -212,7 +214,8 @@ async def create_redis_pool(
     timeout=None,
     pool_cls=None,
     connection_cls=None,
-    loop=None
+    loop=None,
+    name=None
 ):
     """Creates high-level Redis interface.
 
@@ -231,5 +234,6 @@ async def create_redis_pool(
         pool_cls=pool_cls,
         connection_cls=connection_cls,
         loop=loop,
+        name=name
     )
     return commands_factory(pool)
diff --git a/aioredis/connection.py b/aioredis/connection.py
--- a/aioredis/connection.py
+++ b/aioredis/connection.py
@@ -63,7 +63,8 @@ async def create_connection(
     parser=None,
     loop=None,
     timeout=None,
-    connection_cls=None
+    connection_cls=None,
+    name=None
 ):
     """Creates redis connection.
 
@@ -148,6 +149,8 @@ async def create_connection(
             await conn.auth(password)
         if db is not None:
             await conn.select(db)
+        if name is not None:
+            await conn.setname(name)
     except Exception:
         conn.close()
         await conn.wait_closed()
@@ -159,20 +162,15 @@ class RedisConnection(AbcConnection):
     """Redis connection."""
 
     def __init__(
-        self, reader, writer, *, address, encoding=None, parser=None, loop=None
+        self, reader, writer, *, address, encoding=None, parser=None, loop=None, name=None
     ):
         if loop is not None and sys.version_info >= (3, 8):
             warnings.warn("The loop argument is deprecated", DeprecationWarning)
         if parser is None:
             parser = Reader
-        assert callable(parser), ("Parser argument is not callable", parser)
-        self._reader = reader
-        self._writer = writer
-        self._address = address
         self._waiters = deque()
         self._reader.set_parser(
             parser(protocolError=ProtocolError, replyError=ReplyError)
-        )
         self._reader_task = asyncio.ensure_future(self._read_data())
         self._close_msg = None
         self._db = 0
@@ -187,6 +185,7 @@ def __init__(
         self._pubsub_patterns = coerced_keys_dict()
         self._encoding = encoding
         self._pipeline_buffer = None
+        self._name = name
 
     def __repr__(self):
         return "<RedisConnection [db:{}]>".format(self._db)
@@ -571,3 +570,8 @@ def auth(self, password):
         """Authenticate to server."""
         fut = self.execute("AUTH", password)
         return wait_ok(fut)
+
+    def setname(self, name):
+        """Set the current connection name."""
+        fut = self.execute(b'CLIENT', b'SETNAME', name)
+        return wait_ok(fut)
diff --git a/aioredis/pool.py b/aioredis/pool.py
--- a/aioredis/pool.py
+++ b/aioredis/pool.py
@@ -25,7 +25,8 @@ async def create_pool(
     loop=None,
     create_connection_timeout=None,
     pool_cls=None,
-    connection_cls=None
+    connection_cls=None,
+    name=None
 ):
     # FIXME: rewrite docstring
     """Creates Redis Pool.
@@ -76,6 +77,7 @@ async def create_pool(
         create_connection_timeout=create_connection_timeout,
         connection_cls=connection_cls,
         loop=loop,
+        name=name
     )
     try:
         await pool._fill_free(override_min=False)
@@ -102,7 +104,8 @@ def __init__(
         parser=None,
         create_connection_timeout=None,
         connection_cls=None,
-        loop=None
+        loop=None,
+        name=None
     ):
         assert isinstance(minsize, int) and minsize >= 0, (
             "minsize must be int >= 0",
@@ -133,6 +136,7 @@ def __init__(
         self._close_state = CloseEvent(self._do_close)
         self._pubsub_conn = None
         self._connection_cls = connection_cls
+        self._name = name
 
     def __repr__(self):
         return "<{} [db:{}, size:[{}:{}], free:{}]>".format(
@@ -331,6 +335,13 @@ async def auth(self, password):
             for i in range(self.freesize):
                 await self._pool[i].auth(password)
 
+    async def setname(self, name):
+        """Set the current connection name."""
+        self._name = name
+        async with self._cond:
+            for i in range(self.freesize):
+                await self._pool[i].setname(name)
+
     @property
     def in_pubsub(self):
         if self._pubsub_conn and not self._pubsub_conn.closed:
@@ -447,6 +458,7 @@ def _create_new_connection(self, address):
             parser=self._parser_class,
             timeout=self._create_connection_timeout,
             connection_cls=self._connection_cls,
+            name=self._name
         )
 
     async def _wakeup(self, closing_conn=None):


Test patch:
diff --git a/tests/connection_test.py b/tests/connection_test.py
--- a/tests/connection_test.py
+++ b/tests/connection_test.py
@@ -522,3 +522,10 @@ async def test_create_connection__unix_url(create_connection, server_unix_url, k
     assert await conn.execute("ping") == pong
     assert conn.db == db
     assert conn.encoding == enc
+
+
+async def test_connect_setname(request, create_connection, server):
+    name = 'test'
+    conn = await create_connection(server.tcp_address, name=name)
+    res = await conn.execute(b'CLIENT', b'GETNAME')
+    assert res == bytes(name, 'utf-8')
diff --git a/tests/pool_test.py b/tests/pool_test.py
--- a/tests/pool_test.py
+++ b/tests/pool_test.py
@@ -527,3 +527,18 @@ async def test_pool__drop_closed(create_pool, server):
     pool._drop_closed()
     assert pool.freesize == 1
     assert pool.size == 1
+
+
+async def test_client_name(create_pool, server):
+    name = 'test'
+    pool = await create_pool(server.tcp_address, name=name)
+
+    with (await pool) as conn:
+        res = await conn.execute(b'CLIENT', b'GETNAME')
+        assert res == bytes(name, 'utf-8')
+
+    name = 'test2'
+    await pool.setname(name)
+    with (await pool) as conn:
+        res = await conn.execute(b'CLIENT', b'GETNAME')
+        assert res == bytes(name, 'utf-8')