import logging import threading from pydantic import BaseModel from typing import Any, Optional from gitea.models import IssueModel, PullRequestModel logger: logging.Logger = logging.getLogger("work-queue") class WorkItem(BaseModel): repo_full_name: str task_type: str # 'issue' or 'pr' task_number: int task_info: IssueModel | PullRequestModel notification_id: Optional[int] = None priority: int = 0 class WorkQueue: """Thread-safe work queue grouped by repo.""" def __init__(self) -> None: self._lock: threading.Lock = threading.Lock() self._queue: list[WorkItem] = [] self._enqueued_repos: set[str] = set() def enqueue(self, item: WorkItem) -> None: with self._lock: self._queue.append(item) self._enqueued_repos.add(item.repo_full_name) logger.info(f"Enqueued work item: {item.task_type} #{item.task_number} for {item.repo_full_name}") def enqueue_batch(self, items: list[WorkItem]) -> None: with self._lock: for item in items: self._queue.append(item) self._enqueued_repos.add(item.repo_full_name) logger.info(f"Enqueued work item: {item.task_type} #{item.task_number} for {item.repo_full_name}") def get_repo_work(self, repo: str) -> list[WorkItem]: """Get all work items for a specific repo.""" with self._lock: items: list[WorkItem] = [ item for item in self._queue if item.repo_full_name == repo ] logger.info(f"Retrieved {len(items)} work items for repository: {repo}") return items def remove_repo_work(self, repo: str) -> None: """Remove all work items for a specific repo.""" with self._lock: self._queue = [ item for item in self._queue if item.repo_full_name != repo ] self._enqueued_repos.discard(repo) logger.info(f"Removed all work items for repository: {repo}") def get_next_repo(self) -> str | None: """Get the next repo with work, or None if empty.""" with self._lock: if not self._enqueued_repos: return None return next(iter(self._enqueued_repos)) @property def is_empty(self) -> bool: with self._lock: return len(self._queue) == 0 def __len__(self) -> int: with self._lock: return len(self._queue)