Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
async def test_lock_one_of_two_instances_failed(
self, mock_redis_two_instances,
method_name, call_args
):
redis, pool = mock_redis_two_instances
pool.eval = CoroutineMock(side_effect=[EVAL_ERROR, EVAL_OK])
method = getattr(redis, method_name)
script = getattr(redis.instances[0], '%s_script' % method_name)
with pytest.raises(LockError):
await method('resource', 'lock_id')
calls = [call(script, **call_args)] * 2
pool.eval.assert_has_calls(calls)
self,
mock_redis_three_instances,
redis_result,
success,
method_name, call_args
):
redis, pool = mock_redis_three_instances
pool.eval = CoroutineMock(side_effect=redis_result)
method = getattr(redis, method_name)
script = getattr(redis.instances[0], '%s_script' % method_name)
if success:
await method('resource', 'lock_id')
else:
with pytest.raises(LockError):
await method('resource', 'lock_id')
calls = [call(script, **call_args)] * 3
pool.eval.assert_has_calls(calls)
"""
try:
with await self.connect() as redis:
await redis.eval(
self.unset_lock_script,
keys=[resource],
args=[lock_identifier]
)
except aioredis.errors.ReplyError as exc: # script fault
self.log.debug('Can not unset lock "%s" on %s',
resource, repr(self))
raise LockError('Can not unset lock') from exc
except (aioredis.errors.RedisError, OSError) as exc:
self.log.error('Can not unset lock "%s" on %s: %s',
resource, repr(self), repr(exc))
raise LockError('Can not set lock') from exc
except asyncio.CancelledError:
self.log.debug('Lock "%s" unset is cancelled on %s',
resource, repr(self))
raise
except Exception as exc:
self.log.exception('Can not unset lock "%s" on %s',
resource, repr(self))
raise
else:
self.log.debug('Lock "%s" is unset on %s', resource, repr(self))
async def cleanup():
self.log.debug('Cleaning up lock "%s"', resource)
with contextlib.suppress(LockError):
await self.redis.unset_lock(resource, lock_identifier)
"""
lock_identifier = str(uuid.uuid4())
error = RuntimeError('Retry count less then one')
try:
# global try/except to catch CancelledError
for n in range(self.retry_count):
self.log.debug('Acquiring lock "%s" try %d/%d',
resource, n + 1, self.retry_count)
if n != 0:
delay = random.uniform(self.retry_delay_min,
self.retry_delay_max)
await asyncio.sleep(delay)
try:
elapsed_time = await self.redis.set_lock(resource, lock_identifier)
except LockError as exc:
error = exc
continue
if self.lock_timeout - elapsed_time - self.drift <= 0:
error = LockError('Lock timeout')
self.log.debug('Timeout in acquiring the lock "%s"',
resource)
continue
error = None
break
else:
# break never reached
raise error
except Exception as exc:
start_time = time.time()
successes = await asyncio.gather(*[
i.unset_lock(resource, lock_identifier) for
i in self.instances
], return_exceptions=True)
successful_remvoes = sum(s is None for s in successes)
elapsed_time = time.time() - start_time
unlocked = True if successful_remvoes >= int(len(self.instances) / 2) + 1 else False
self.log.debug('Lock "%s" is unset on %d/%d instances in %s seconds',
resource, successful_remvoes, len(self.instances), elapsed_time)
if not unlocked:
raise LockError('Can not release the lock')
return elapsed_time
Unlock this instance
:param resource: redis key to set
:param lock_identifier: uniquie id of lock
:raises: LockError if the lock resource acquired with different lock_identifier
"""
try:
with await self.connect() as redis:
await redis.eval(
self.unset_lock_script,
keys=[resource],
args=[lock_identifier]
)
except aioredis.errors.ReplyError as exc: # script fault
self.log.debug('Can not unset lock "%s" on %s',
resource, repr(self))
raise LockError('Can not unset lock') from exc
except (aioredis.errors.RedisError, OSError) as exc:
self.log.error('Can not unset lock "%s" on %s: %s',
resource, repr(self), repr(exc))
raise LockError('Can not set lock') from exc
except asyncio.CancelledError:
self.log.debug('Lock "%s" unset is cancelled on %s',
resource, repr(self))
raise
except Exception as exc:
self.log.exception('Can not unset lock "%s" on %s',
resource, repr(self))
raise
else:
self.log.debug('Lock "%s" is unset on %s', resource, repr(self))
# global try/except to catch CancelledError
for n in range(self.retry_count):
self.log.debug('Acquiring lock "%s" try %d/%d',
resource, n + 1, self.retry_count)
if n != 0:
delay = random.uniform(self.retry_delay_min,
self.retry_delay_max)
await asyncio.sleep(delay)
try:
elapsed_time = await self.redis.set_lock(resource, lock_identifier)
except LockError as exc:
error = exc
continue
if self.lock_timeout - elapsed_time - self.drift <= 0:
error = LockError('Lock timeout')
self.log.debug('Timeout in acquiring the lock "%s"',
resource)
continue
error = None
break
else:
# break never reached
raise error
except Exception as exc:
# cleanup in case of fault or cancellation will run in background
async def cleanup():
self.log.debug('Cleaning up lock "%s"', resource)
with contextlib.suppress(LockError):
await self.redis.unset_lock(resource, lock_identifier)