Spaces:
Running
Running
File size: 2,923 Bytes
86d6248 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
import asyncio
import redis.asyncio as redis
from datetime import datetime
from collections import defaultdict
from typing import Dict
class Analytics:
def __init__(self, redis_url: str, sync_interval: int = 60):
"""
Initializes the Analytics class with an async Redis connection and sync interval.
Parameters:
- redis_url: Redis connection URL (e.g., 'redis://localhost:6379/0')
- sync_interval: Interval in seconds for syncing with Redis.
"""
self.pool = redis.ConnectionPool.from_url(redis_url, decode_responses=True)
self.redis_client = redis.Redis(connection_pool=self.pool)
self.local_buffer = defaultdict(
lambda: defaultdict(int)
) # {period: {model_id: count}}
self.sync_interval = sync_interval
self.lock = asyncio.Lock() # Async lock for thread-safe updates
asyncio.create_task(self._start_sync_task())
def _get_period_keys(self) -> tuple:
"""
Returns keys for day, week, month, and year based on the current date.
"""
now = datetime.utcnow()
day_key = now.strftime("%Y-%m-%d")
week_key = f"{now.year}-W{now.strftime('%U')}"
month_key = now.strftime("%Y-%m")
year_key = now.strftime("%Y")
return day_key, week_key, month_key, year_key
async def access(self, model_id: str):
"""
Records an access for a specific model_id.
"""
day_key, week_key, month_key, year_key = self._get_period_keys()
async with self.lock:
self.local_buffer[day_key][model_id] += 1
self.local_buffer[week_key][model_id] += 1
self.local_buffer[month_key][model_id] += 1
self.local_buffer[year_key][model_id] += 1
self.local_buffer["total"][model_id] += 1
async def stats(self) -> Dict[str, Dict[str, int]]:
"""
Returns statistics for all models from the local buffer.
"""
async with self.lock:
return {
period: dict(models) for period, models in self.local_buffer.items()
}
async def _sync_to_redis(self):
"""
Synchronizes local buffer data with Redis.
"""
async with self.lock:
pipeline = self.redis_client.pipeline()
for period, models in self.local_buffer.items():
for model_id, count in models.items():
redis_key = f"analytics:{period}"
pipeline.hincrby(redis_key, model_id, count)
await pipeline.execute()
self.local_buffer.clear() # Clear the buffer after sync
async def _start_sync_task(self):
"""
Starts a background task that periodically syncs data to Redis.
"""
while True:
await asyncio.sleep(self.sync_interval)
await self._sync_to_redis()
|