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'}
|