Skip to content

Commit eb22388

Browse files
ritwik-gclaude
andcommitted
Address PR review comments: remove dead code and clarify TTL behavior
1. Remove deprecated acquire_slot() method (PR comment #1) - Method marked as deprecated, not used anywhere in codebase - check_and_acquire() is the only method used (atomic operation) - Dead code removal improves maintainability 2. Add detailed comment explaining TTL vs manual cleanup (PR comment #2) - Clarifies why _cleanup_expired_entries() is needed even with TTL - Redis ZSET TTL expires entire key, not individual entries - Manual cleanup (ZREMRANGEBYSCORE) removes stale entries within ZSET - Both mechanisms work together for accurate rate limiting 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 434f7ec commit eb22388

1 file changed

Lines changed: 7 additions & 43 deletions

File tree

backend/api_v2/rate_limiter.py

Lines changed: 7 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ def get_current_usage(cls, organization: Organization) -> dict:
120120
org_key = cls._get_org_key(str(organization.organization_id))
121121

122122
# Cleanup expired entries before counting
123+
# NOTE: Manual cleanup is required even though ZSET keys have TTL because:
124+
# 1. Redis TTL expires the entire ZSET key after inactivity, not individual entries
125+
# 2. Individual ZSET entries remain until the whole key expires
126+
# 3. Without cleanup, stale entries skew the count and cause incorrect rate limiting
127+
# 4. ZREMRANGEBYSCORE removes entries older than 6 hours (keeps count accurate)
128+
# 5. TTL (expire) garbage collects the entire key if org becomes inactive
129+
# Both mechanisms work together: manual cleanup + key TTL
123130
cls._cleanup_expired_entries(org_key)
124131
cls._cleanup_expired_entries(RateLimitKeys.GLOBAL_EXECUTIONS_KEY)
125132

@@ -333,49 +340,6 @@ def check_rate_limit(cls, organization: Organization) -> tuple[bool, dict | None
333340
)
334341
return True, None
335342

336-
@classmethod
337-
def acquire_slot(cls, organization: Organization, execution_id: str) -> bool:
338-
"""Reserve a rate limit slot for a new execution.
339-
340-
DEPRECATED: Use check_and_acquire() instead for atomic check-and-acquire.
341-
This method is kept for backward compatibility.
342-
343-
Args:
344-
organization: Organization instance
345-
execution_id: Unique execution identifier
346-
347-
Returns:
348-
bool: True if slot was successfully acquired
349-
"""
350-
org_key = cls._get_org_key(str(organization.organization_id))
351-
current_timestamp = time.time()
352-
ttl_seconds = cls._get_ttl_seconds()
353-
354-
try:
355-
# Use pipeline for atomic operations
356-
pipe = redis_cache.pipeline()
357-
358-
# Add to org-specific ZSET
359-
pipe.zadd(org_key, {execution_id: current_timestamp})
360-
pipe.expire(org_key, ttl_seconds)
361-
362-
# Add to global ZSET
363-
pipe.zadd(
364-
RateLimitKeys.GLOBAL_EXECUTIONS_KEY, {execution_id: current_timestamp}
365-
)
366-
pipe.expire(RateLimitKeys.GLOBAL_EXECUTIONS_KEY, ttl_seconds)
367-
368-
pipe.execute()
369-
370-
logger.info(
371-
f"Rate limit slot acquired for org {organization.organization_id}, "
372-
f"execution {execution_id}"
373-
)
374-
return True
375-
except Exception as e:
376-
logger.error(f"Failed to acquire rate limit slot: {e}")
377-
return False
378-
379343
@classmethod
380344
def release_slot(cls, organization_id: str, execution_id: str) -> None:
381345
"""Release a rate limit slot when execution completes.

0 commit comments

Comments
 (0)