from __future__ import annotations import logging import time from collections import defaultdict logger = logging.getLogger(__name__) class JiraLoopBreaker: def __init__(self, max_comments_per_issue_per_minute: int = 8): self._counters: dict[str, list[float]] = defaultdict(list) self._max = max_comments_per_issue_per_minute self._tripped: dict[str, float] = {} def record_and_check(self, issue_key: str) -> bool: now = time.monotonic() window = [t for t in self._counters.get(issue_key, []) if now - t < 60] if len(window) >= self._max: self._tripped[issue_key] = now logger.warning( "Jira loop breaker tripped for issue=%s, comments=%d", issue_key, len(window), ) return False window.append(now) self._counters[issue_key] = window return True def is_tripped(self, issue_key: str) -> bool: now = time.monotonic() trip_time = self._tripped.get(issue_key) if trip_time and now - trip_time < 300: return True if trip_time and now - trip_time >= 300: del self._tripped[issue_key] return False def reset_issue(self, issue_key: str): self._counters.pop(issue_key, None) self._tripped.pop(issue_key, None)