35 lines
1018 B
Python
35 lines
1018 B
Python
"""Redis 分布式锁(SET NX EX)。"""
|
||
import secrets
|
||
import time
|
||
|
||
import redis.asyncio as aioredis
|
||
|
||
from app.config import settings
|
||
|
||
|
||
class Lock:
|
||
def __init__(self, redis: aioredis.Redis, name: str, timeout: int = settings.lock_timeout):
|
||
self.redis = redis
|
||
self.name = name
|
||
self.timeout = timeout
|
||
self._token = secrets.token_hex(8)
|
||
|
||
async def acquire(self) -> bool:
|
||
ok = await self.redis.set(self.name, self._token, nx=True, ex=self.timeout)
|
||
return bool(ok)
|
||
|
||
async def release(self) -> None:
|
||
# 仅在持有相同 token 时释放,避免误删他人锁
|
||
val = await self.redis.get(self.name)
|
||
if val == self._token:
|
||
await self.redis.delete(self.name)
|
||
|
||
async def guarded(self, fn):
|
||
"""上下文封装:获取锁执行,释放锁。"""
|
||
if not await self.acquire():
|
||
return False
|
||
try:
|
||
await fn()
|
||
return True
|
||
finally:
|
||
await self.release() |