feat(co-gahusb): 어드바이저리 락 (acquire/release/heartbeat/list, TDD)
This commit is contained in:
66
co-gahusb/app/locks.py
Normal file
66
co-gahusb/app/locks.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# co-gahusb/app/locks.py
|
||||
from redis.exceptions import WatchError
|
||||
|
||||
LOCK_PREFIX = "co:lock:"
|
||||
|
||||
|
||||
async def acquire_lock(r, resource, role, ttl_sec=300):
|
||||
key = LOCK_PREFIX + resource
|
||||
ok = await r.set(key, role, nx=True, ex=ttl_sec)
|
||||
if ok:
|
||||
return {"acquired": True}
|
||||
held_by = await r.get(key)
|
||||
ttl = await r.ttl(key)
|
||||
return {"acquired": False, "held_by": held_by, "ttl_remaining": max(ttl, 0)}
|
||||
|
||||
|
||||
async def release_lock(r, resource, role):
|
||||
key = LOCK_PREFIX + resource
|
||||
async with r.pipeline() as pipe:
|
||||
while True:
|
||||
try:
|
||||
await pipe.watch(key)
|
||||
owner = await pipe.get(key)
|
||||
if owner != role:
|
||||
await pipe.unwatch()
|
||||
return {"released": False, "held_by": owner}
|
||||
pipe.multi()
|
||||
pipe.delete(key)
|
||||
await pipe.execute()
|
||||
return {"released": True}
|
||||
except WatchError:
|
||||
continue
|
||||
|
||||
|
||||
async def heartbeat_lock(r, resource, role, ttl_sec=300):
|
||||
key = LOCK_PREFIX + resource
|
||||
async with r.pipeline() as pipe:
|
||||
while True:
|
||||
try:
|
||||
await pipe.watch(key)
|
||||
owner = await pipe.get(key)
|
||||
if owner != role:
|
||||
await pipe.unwatch()
|
||||
return {"renewed": False, "held_by": owner}
|
||||
pipe.multi()
|
||||
pipe.expire(key, ttl_sec)
|
||||
await pipe.execute()
|
||||
return {"renewed": True}
|
||||
except WatchError:
|
||||
continue
|
||||
|
||||
|
||||
async def list_locks(r):
|
||||
keys = await r.keys(LOCK_PREFIX + "*")
|
||||
out = []
|
||||
for key in keys:
|
||||
held_by = await r.get(key)
|
||||
if held_by is None:
|
||||
continue
|
||||
ttl = await r.ttl(key)
|
||||
out.append({
|
||||
"resource": key[len(LOCK_PREFIX):],
|
||||
"held_by": held_by,
|
||||
"ttl_remaining": max(ttl, 0),
|
||||
})
|
||||
return {"locks": out}
|
||||
Reference in New Issue
Block a user