Here is the refactored job queue package split into a proper modular structure. Each file adheres to single-responsibility principles, maintains clear separation of concerns, and provides a clean public API via `__init__.py`.

---

### `queue/__init__.py`

```python
"""Job Queue Package - A modular job queue system with priority and retry support."""

from queue.core import Job, JobQueue
from queue.retry import RetryHandler, RetryConfig
from queue.priority import PriorityQueue

__all__ = [
    "Job",
    "JobQueue",
    "PriorityQueue",
    "RetryHandler",
    "RetryConfig",
]
```

---

### `queue/core.py`

```python
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Callable, Optional
from collections import deque
import uuid


@dataclass
class Job:
    """Represents a job to be processed."""
    id: str = field(default_factory=lambda: str(uuid.uuid4()))
    name: str = ""
    payload: Any = None
    status: str = "pending"
    created_at: datetime = field(default_factory=datetime.utcnow)
    updated_at: Optional[datetime] = None
    retry_count: int = 0
    max_retries: int = 3
    error: Optional[str] = None
    result: Any = None
    scheduled_at: Optional[datetime] = None

    def __post_init__(self):
        if not self.id:
            self.id = str(uuid.uuid4())

    def mark_started(self):
        self.status = "running"
        self.updated_at = datetime.utcnow()

    def mark_completed(self, result: Any = None):
        self.status = "completed"
        self.result = result
        self.updated_at = datetime.utcnow()

    def mark_failed(self, error: str):
        self.status = "failed"
        self.error = error
        self.updated_at = datetime.utcnow()

    def mark_scheduled(self, scheduled_at: datetime):
        self.status = "scheduled"
        self.scheduled_at = scheduled_at
        self.updated_at = datetime.utcnow()

    def is_ready(self) -> bool:
        if self.status != "scheduled":
            return True
        return self.scheduled_at is None or datetime.utcnow() >= self.scheduled_at


class JobQueue:
    """A basic FIFO queue for jobs."""

    def __init__(self):
        self._queue: deque[Job] = deque()

    def enqueue(self, job: Job) -> None:
        self._queue.append(job)

    def dequeue(self) -> Optional[Job]:
        if self._queue:
            return self._queue.popleft()
        return None

    def peek(self) -> Optional[Job]:
        return self._queue[0] if self._queue else None

    def size(self) -> int:
        return len(self._queue)

    def is_empty(self) -> bool:
        return len(self._queue) == 0

    def clear(self) -> None:
        self._queue.clear()
```

---

### `queue/priority.py`

```python
import heapq
from typing import Optional, Any, Callable
from queue.core import Job, JobQueue


class PriorityQueue(JobQueue):
    """A priority queue that orders jobs based on priority value."""

    def __init__(self, priority_key: Callable[[Job], int] = lambda job: job.priority if hasattr(job, 'priority') else 0):
        super().__init__()
        self._heap: list[tuple[int, int, Job]] = []
        self._counter = 0
        self._priority_key = priority_key

    def enqueue(self, job: Job) -> None:
        priority = self._priority_key(job)
        heapq.heappush(self._heap, (priority, self._counter, job))
        self._counter += 1

    def dequeue(self) -> Optional[Job]:
        if self._heap:
            _, _, job = heapq.heappop(self._heap)
            return job
        return None

    def peek(self) -> Optional[Job]:
        return self._heap[0][2] if self._heap else None

    def size(self) -> int:
        return len(self._heap)

    def is_empty(self) -> bool:
        return len(self._heap) == 0

    def clear(self) -> None:
        self._heap.clear()
        self._counter = 0
```

---

### `queue/retry.py`

```python
import time
from typing import Callable, Optional, Any
from queue.core import Job
from datetime import datetime, timedelta
import math


class RetryConfig:
    """Configuration for retry behavior."""

    def __init__(
        self,
        max_retries: int = 3,
        base_delay: float = 1.0,
        max_delay: float = 60.0,
        exponential_base: float = 2.0,
        jitter: bool = True
    ):
        self.max_retries = max_retries
        self.base_delay = base_delay
        self.max_delay = max_delay
        self.exponential_base = exponential_base
        self.jitter = jitter

    def get_delay(self, attempt: int) -> float:
        delay = self.base_delay * (self.exponential_base ** attempt)
        delay = min(delay, self.max_delay)
        if self.jitter:
            delay *= 0.5 * (1 + math.random())
        return delay


class RetryHandler:
    """Handles job retry logic with exponential backoff."""

    def __init__(self, config: Optional[RetryConfig] = None):
        self.config = config or RetryConfig()

    def should_retry(self, job: Job) -> bool:
        return job.retry_count < job.max_retries

    def get_next_retry_delay(self, job: Job) -> float:
        return self.config.get_delay(job.retry_count)

    def process_with_retry(self, job: Job, handler: Callable[[Job], Any]) -> Any:
        last_error = None
        while self.should_retry(job) or job.retry_count <= self.config.max_retries:
            try:
                result = handler(job)
                job.mark_completed(result)
                return result
            except Exception as e:
                last_error = str(e)
                job.retry_count += 1
                job.mark_failed(last_error)
                if self.should_retry(job):
                    delay = self.get_next_retry_delay(job)
                    time.sleep(delay)
        job.mark_failed(last_error)
        raise Exception(f"Job {job.id} failed after {job.retry_count} retries: {last_error}")
```

---

### Summary of Responsibilities

| Module       | Responsibility                            |
|--------------|--------------------------------------------|
| `__init__.py`| Public API exports and package initialization |
| `core.py`    | Job dataclass and basic queue operations    |
| `priority.py`| Priority queue implementation               |
| `retry.py`   | Retry logic with exponential backoff        |

This structure ensures each module has a single responsibility, supports clean imports, and exposes a well-defined public API.