Migrating from v0.3 to v1.0¶
API changes and backward incompatible changes:
aioredis.create_pool¶
create_pool() now returns ConnectionsPool
instead of RedisPool.
This means that pool now operates with RedisConnection
objects and not Redis.
| v0.3 | pool = await aioredis.create_pool(('localhost', 6379))
with await pool as redis:
# calling methods of Redis class
await redis.lpush('list-key', 'item1', 'item2')
|
| v1.0 | pool = await aioredis.create_pool(('localhost', 6379))
with await pool as conn:
# calling conn.lpush will raise AttributeError exception
await conn.execute('lpush', 'list-key', 'item1', 'item2')
|
aioredis.create_reconnecting_redis¶
create_reconnecting_redis() has been dropped.
create_redis_pool() can be used instead of former function.
| v0.3 | redis = await aioredis.create_reconnecting_redis(
('localhost', 6379))
await redis.lpush('list-key', 'item1', 'item2')
|
| v1.0 | redis = await aioredis.create_redis_pool(
('localhost', 6379))
await redis.lpush('list-key', 'item1', 'item2')
|
create_redis_pool returns Redis initialized with
ConnectionsPool which is responsible for reconnecting to server.
Also create_reconnecting_redis was patching the RedisConnection and
breaking closed property (it was always True).
aioredis.Redis¶
Redis class now operates with objects implementing
aioredis.abc.AbcConnection interface.
RedisConnection and ConnectionsPool are
both implementing AbcConnection so it is become possible to use same API
when working with either single connection or connections pool.
| v0.3 | redis = await aioredis.create_redis(('localhost', 6379))
await redis.lpush('list-key', 'item1', 'item2')
pool = await aioredis.create_pool(('localhost', 6379))
redis = await pool.acquire() # get Redis object
await redis.lpush('list-key', 'item1', 'item2')
|
| v1.0 | redis = await aioredis.create_redis(('localhost', 6379))
await redis.lpush('list-key', 'item1', 'item2')
redis = await aioredis.create_redis_pool(('localhost', 6379))
await redis.lpush('list-key', 'item1', 'item2')
|
Blocking operations and connection sharing¶
Current implementation of ConnectionsPool by default execute
every command on random connection. The Pros of this is that it allowed
implementing AbcConnection interface and hide pool inside Redis class,
and also keep pipelining feature (like RedisConnection.execute).
The Cons of this is that different tasks may use same connection and block
it with some long-running command.
We can call it Shared Mode — commands are sent to random connections in pool without need to lock [connection]:
redis = await aioredis.create_redis_pool(
('localhost', 6379),
minsize=1,
maxsize=1)
async def task():
# Shared mode
await redis.set('key', 'val')
asyncio.ensure_future(task())
asyncio.ensure_future(task())
# Both tasks will send commands through same connection
# without acquiring (locking) it first.
Blocking operations (like blpop, brpop or long-running LUA scripts)
in shared mode mode will block connection and thus may lead to whole
program malfunction.
This blocking issue can be easily solved by using exclusive connection for such operations:
redis = await aioredis.create_redis_pool(
('localhost', 6379),
minsize=1,
maxsize=1)
async def task():
# Exclusive mode
with await redis as r:
await r.set('key', 'val')
asyncio.ensure_future(task())
asyncio.ensure_future(task())
# Both tasks will first acquire connection.
We can call this Exclusive Mode — context manager is used to acquire (lock) exclusive connection from pool and send all commands through it.
Note
This technique is similar to v0.3 pool usage:
# in aioredis v0.3
pool = await aioredis.create_pool(('localhost', 6379))
with await pool as redis:
# Redis is bound to exclusive connection
redis.set('key', 'val')
Sorted set commands return values¶
Sorted set commands (like zrange, zrevrange and others) that accept
withscores argument now return list of tuples instead of plain list.
| v0.3 | redis = await aioredis.create_redis(('localhost', 6379))
await redis.zadd('zset-key', 1, 'one', 2, 'two')
res = await redis.zrage('zset-key', withscores=True)
assert res == [b'one', 1, b'two', 2]
# not an esiest way to make a dict
it = iter(res)
assert dict(zip(it, it)) == {b'one': 1, b'two': 2}
|
| v1.0 | redis = await aioredis.create_redis(('localhost', 6379))
await redis.zadd('zset-key', 1, 'one', 2, 'two')
res = await redis.zrage('zset-key', withscores=True)
assert res == [(b'one', 1), (b'two', 2)]
# now its easier to make a dict of it
assert dict(res) == {b'one': 1, b'two': 2}
|
Hash hscan command now returns list of tuples¶
hscan updated to return a list of tuples instead of plain
mixed key/value list.
| v0.3 | redis = await aioredis.create_redis(('localhost', 6379))
await redis.hmset('hash', 'one', 1, 'two', 2)
cur, data = await redis.hscan('hash')
assert data == [b'one', b'1', b'two', b'2']
# not an esiest way to make a dict
it = iter(data)
assert dict(zip(it, it)) == {b'one': b'1', b'two': b'2'}
|
| v1.0 | redis = await aioredis.create_redis(('localhost', 6379))
await redis.hmset('hash', 'one', 1, 'two', 2)
cur, data = await redis.hscan('hash')
assert data == [(b'one', b'1'), (b'two', b'2')]
# now its easier to make a dict of it
assert dict(data) == {b'one': b'1': b'two': b'2'}
|