feat: add tests for import polling, login page, money utilities, and query keys
- Implemented tests for import polling functionality, ensuring correct behavior for active and terminal import statuses. - Created tests for the login page, validating user interactions and error handling. - Added unit tests for money utility functions, covering parsing, formatting, and summation of monetary values. - Developed tests for query keys, ensuring proper scoping and invalidation roots. chore: setup testing environment and configuration - Added setup file for testing with Vitest and Testing Library. - Configured TypeScript and Vite for the frontend project. - Created Docker and Nginx configurations for local development and production environments. - Established a PostgreSQL initialization script for setting up application roles. docs: add README and environment configuration for infra - Included README for the infra directory, detailing local development setup and service descriptions. - Created an example environment configuration file for local development with placeholders for sensitive information.
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import hashlib
|
||||
import threading
|
||||
import time
|
||||
from collections import defaultdict, deque
|
||||
|
||||
from redis import Redis
|
||||
from redis.exceptions import RedisError
|
||||
|
||||
from app.config import get_settings
|
||||
|
||||
_lock = threading.Lock()
|
||||
_hits: dict[str, deque[float]] = defaultdict(deque)
|
||||
|
||||
|
||||
def allow(key: str, limit: int, window_seconds: float) -> bool:
|
||||
"""Distributed fixed-window limiter with a local fail-safe fallback."""
|
||||
digest = hashlib.sha256(key.encode()).hexdigest()
|
||||
window = int(time.time() // window_seconds)
|
||||
try:
|
||||
client = Redis.from_url(
|
||||
get_settings().redis_url,
|
||||
socket_connect_timeout=0.2,
|
||||
socket_timeout=0.2,
|
||||
)
|
||||
redis_key = f"rate:{digest}:{window}"
|
||||
with client.pipeline() as pipeline:
|
||||
pipeline.incr(redis_key)
|
||||
pipeline.expire(redis_key, int(window_seconds) + 1)
|
||||
count, _ = pipeline.execute()
|
||||
return int(count) <= limit
|
||||
except RedisError:
|
||||
pass
|
||||
|
||||
now = time.monotonic()
|
||||
with _lock:
|
||||
bucket = _hits[digest]
|
||||
while bucket and bucket[0] <= now - window_seconds:
|
||||
bucket.popleft()
|
||||
if len(bucket) >= limit:
|
||||
return False
|
||||
bucket.append(now)
|
||||
return True
|
||||
Reference in New Issue
Block a user