gateway: add public invoke/jobs facade with redis queue worker and SSE
This commit is contained in:
84
gateway-bot/daarion_facade/redis_jobs.py
Normal file
84
gateway-bot/daarion_facade/redis_jobs.py
Normal file
@@ -0,0 +1,84 @@
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from redis.asyncio import Redis
|
||||
|
||||
REDIS_URL = os.getenv("REDIS_URL", "redis://redis:6379/0")
|
||||
JOB_KEY_PREFIX = "daarion:jobs"
|
||||
QUEUE_KEY = "daarion:jobs:queue"
|
||||
JOB_TTL_SECONDS = int(os.getenv("DAARION_JOB_TTL_SECONDS", str(72 * 3600)))
|
||||
|
||||
_redis: Optional[Redis] = None
|
||||
|
||||
|
||||
def _job_key(job_id: str) -> str:
|
||||
return f"{JOB_KEY_PREFIX}:{job_id}"
|
||||
|
||||
|
||||
async def redis_client() -> Redis:
|
||||
global _redis
|
||||
if _redis is None:
|
||||
_redis = Redis.from_url(REDIS_URL, decode_responses=True)
|
||||
return _redis
|
||||
|
||||
|
||||
async def close_redis() -> None:
|
||||
global _redis
|
||||
if _redis is not None:
|
||||
await _redis.close()
|
||||
_redis = None
|
||||
|
||||
|
||||
async def create_job(job_id: str, payload: Dict[str, Any]) -> None:
|
||||
r = await redis_client()
|
||||
key = _job_key(job_id)
|
||||
await r.set(key, json.dumps(payload, ensure_ascii=False), ex=JOB_TTL_SECONDS)
|
||||
|
||||
|
||||
async def get_job(job_id: str) -> Optional[Dict[str, Any]]:
|
||||
r = await redis_client()
|
||||
raw = await r.get(_job_key(job_id))
|
||||
if not raw:
|
||||
return None
|
||||
try:
|
||||
return json.loads(raw)
|
||||
except json.JSONDecodeError:
|
||||
return None
|
||||
|
||||
|
||||
async def update_job(job_id: str, patch: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||
current = await get_job(job_id)
|
||||
if not current:
|
||||
return None
|
||||
current.update(patch)
|
||||
await create_job(job_id, current)
|
||||
return current
|
||||
|
||||
|
||||
async def enqueue_job(job_id: str) -> None:
|
||||
r = await redis_client()
|
||||
await r.lpush(QUEUE_KEY, job_id)
|
||||
|
||||
|
||||
async def dequeue_job(block_seconds: int = 5) -> Optional[str]:
|
||||
r = await redis_client()
|
||||
result = await r.brpop(QUEUE_KEY, timeout=block_seconds)
|
||||
if not result:
|
||||
return None
|
||||
_, job_id = result
|
||||
return job_id
|
||||
|
||||
|
||||
async def wait_for_redis(timeout_seconds: int = 30) -> None:
|
||||
deadline = asyncio.get_running_loop().time() + timeout_seconds
|
||||
while True:
|
||||
try:
|
||||
r = await redis_client()
|
||||
await r.ping()
|
||||
return
|
||||
except Exception:
|
||||
if asyncio.get_running_loop().time() >= deadline:
|
||||
raise
|
||||
await asyncio.sleep(1)
|
||||
Reference in New Issue
Block a user