| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- import json
- import logging
- import time
- from typing import Any, Optional
- import redis
- from app.config import settings
- from app.repository.record_interface import RecordInterface
- from app.repository.task_record import TaskRecord
- logger = logging.getLogger(__name__)
- TASK_KEY_PREFIX = "task:"
- class RedisRecordStore(RecordInterface):
- def __init__(self):
- self._client = redis.Redis(
- host=settings.redis_host,
- port=settings.redis_port,
- password=settings.redis_password,
- db=settings.redis_db,
- socket_timeout=settings.redis_timeout / 1000,
- decode_responses=True,
- )
- def _on_save(self, record: TaskRecord):
- try:
- self._client.set(
- TASK_KEY_PREFIX + record.task_id, json.dumps(record.to_dict())
- )
- except Exception as e:
- logger.error("Failed to save task record: %s", e)
- def _on_get(self, task_id: str) -> Optional[TaskRecord]:
- try:
- data = self._client.get(TASK_KEY_PREFIX + task_id)
- if data:
- return TaskRecord.from_dict(json.loads(data))
- return None
- except Exception as e:
- logger.error("Failed to get task record: %s", e)
- return None
- def _on_get_all(self) -> dict[str, TaskRecord]:
- result: dict[str, TaskRecord] = {}
- try:
- keys = self._client.keys(TASK_KEY_PREFIX + "*")
- for key in keys or []:
- task_id = key[len(TASK_KEY_PREFIX):]
- data = self._client.get(key)
- if data:
- result[task_id] = TaskRecord.from_dict(json.loads(data))
- except Exception as e:
- logger.error("Failed to get all tasks: %s", e)
- return result
- def _on_delete(self, max_age_hours: int):
- try:
- cutoff = int(time.time() * 1000) - max_age_hours * 3600 * 1000
- all_records = self._on_get_all()
- for task_id, record in all_records.items():
- if record.status in ("successes", "failed") and record.update_time < cutoff:
- self._client.delete(TASK_KEY_PREFIX + task_id)
- except Exception as e:
- logger.error("Failed to cleanup completed tasks: %s", e)
- def _on_update_status(
- self, task_id: str, status: str, message: str, data: Optional[dict]
- ):
- try:
- record = self._on_get(task_id)
- if record:
- record.status = status
- record.message = message
- record.touch()
- if data is not None:
- record.data = data
- self._on_save(record)
- except Exception as e:
- logger.error("Failed to update task status: %s", e)
- def _on_publish(self, task_id: str):
- if not settings.redis_publish_enabled:
- return
- try:
- record = self._on_get(task_id)
- if record:
- payload = json.dumps(record.to_dict(), ensure_ascii=False)
- receivers = self._client.publish(settings.redis_publish_channel, payload)
- logger.info("Published to channel '%s', receivers=%d",
- settings.redis_publish_channel, receivers)
- except Exception as e:
- logger.error("Failed to publish task event: %s", e)
|