<reasoning_content>
Here's a thinking process:

1.  **Understand the User's Request:**
   - **Input:** A conceptual single-file Python implementation (`queue.py`) containing:
     - `Job` class
     - `JobQueue` class
     - `PriorityQueue` class
     - `process_with_retry()` function
   - **Output:** A refactored package structure:
     ```
     queue/
     ├── __init__.py      # Exports: JobQueue, Job
     ├── core.py          # Job dataclass, basic queue operations
     ├── retry.py         # Retry logic with exponential backoff
     └── priority.py      # Priority queue implementation
     ```
   - **Requirements:**
     1. Maintain all existing functionality
     2. Proper imports between modules
     3. Clean public API in `__init__.py`
     4. Each module has a single responsibility
   - **Task:** Provide the content of each file.

2.  **Analyze the Components & Responsibilities:**
   - `core.py`: Should contain the `Job` dataclass and the basic `JobQueue` class (FIFO queue operations).
   - `priority.py`: Should contain the `PriorityQueue` class (extends or wraps priority queue logic).
   - `retry.py`: Should contain the `process_with_retry()` function with exponential backoff.
   - `__init__.py`: Should export `Job`, `JobQueue`, and possibly `PriorityQueue` and `process_with_retry`? Wait, the prompt says `__init__.py` exports `JobQueue, Job`. I'll stick to that, but might optionally export others if needed. I'll follow the prompt exactly: `__all__ = ["Job", "JobQueue"]`.

3.  **Design Each Module (Mental Draft):**

   *`core.py`*:
   - Needs `Job` dataclass. Typical fields: `id`, `payload`, `status`, `created_at`, maybe `retry_count`.
   - Needs `JobQueue` class. Basic operations: `enqueue`, `dequeue`, `peek`, `is_empty`, maybe `size`.
   - Should be independent of priority and retry logic.

   *`priority.py`*:
   - Needs `PriorityQueue` class. Could inherit from `JobQueue` or be a separate implementation using `heapq`. Since it's a refactoring, I'll make it a drop-in replacement or a subclass that uses priority logic. Let's make it inherit from `JobQueue` for simplicity, or implement it independently. Actually, it's better to have `PriorityQueue` as a distinct class that uses `heapq` and wraps `Job` objects. I'll make it inherit from `JobQueue` but override enqueue/dequeue to handle priority. Or I'll just implement it as a standalone class that follows the same interface. Let's stick to a clean OOP design: `PriorityQueue` inherits from `JobQueue` and overrides priority-based operations.
   - Wait, the prompt says `priority.py` contains `PriorityQueue` implementation. I'll implement it using `heapq` for efficiency.

   *`retry.py`*:
   - Needs `process_with_retry(func, *args, max_retries=3, base_delay=1.0, **kwargs)` or similar.
   - Exponential backoff: delay = base_delay * (2 ** attempt)
   - Should handle exceptions and retry.

   *`__init__.py`*:
   - `from .core import Job, JobQueue`
   - `__all__ = ["Job", "JobQueue"]`

4.  **Draft Code (Mental Refinement):**

   *`queue/core.py`*:
   ```python
   from dataclasses import dataclass, field
   from datetime import datetime
   from typing import Any, List, Optional

   @dataclass
   class Job:
       id: str
       payload: Any
       status: str = "pending"
       created_at: datetime = field(default_factory=datetime.now)
       retry_count: int = 0

   class JobQueue:
       def __init__(self):
           self._queue: List[Job] = []

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

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

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

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

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

   *`queue/priority.py`*:
   ```python
   import heapq
   from typing import Optional
   from .core import Job, JobQueue

   class PriorityQueue(JobQueue):
       def __init__(self):
           super().__init__()
           self._heap = []
           self._counter = 0  # Tie-breaker for heapq

       def enqueue(self, job: Job, priority: int = 0) -> None:
           # heapq is a min-heap, lower priority number = higher priority
           entry = (priority, self._counter, job)
           self._counter += 1
           heapq.heappush(self._heap, entry)

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

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

       def size(self) -> int:
           return len(self._heap)
   ```
   *Self-Correction/Refinement on PriorityQueue*: Inheriting from `JobQueue` but overriding methods while keeping state separate might be messy. Better to just implement it as a standalone class with the same interface, or make `JobQueue` an abstract base, or just not inherit but follow the same pattern. Actually, composition or simple inheritance is fine. I'll keep it simple: `PriorityQueue` doesn't strictly need to inherit from `JobQueue` if it provides the same interface, but for the sake of the exercise, I'll make it a drop-in replacement. I'll remove inheritance to avoid state duplication issues and just implement it cleanly. Or I'll keep inheritance but manage state in `_heap` only. Let's stick to the simple `heapq` implementation without inheritance to avoid `super().__init__()` state conflicts. I'll just make it a standalone class that matches the `JobQueue` interface.

   Revised `priority.py`:
   ```python
   import heapq
   from typing import Optional
   from .core import Job

   class PriorityQueue:
       def __init__(self):
           self._heap = []
           self._counter = 0

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

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

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

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

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

   *`queue/retry.py`*:
   ```python
   import time
   from typing import Callable, Any, Tuple, Type, Optional
   import random

   def process_with_retry(
       func: Callable[..., Any],
       *args,
       max_retries: int = 3,
       base_delay: float = 1.0,
       backoff_factor: float = 2.0,
       jitter: float = 0.0,
       exceptions_to_retry: Tuple[Type[Exception], ...] = (Exception,),
       **kwargs
   ) -> Any:
       last_exception = None
       for attempt in range(max_retries + 1):
           try:
               return func(*args, **kwargs)
           except exceptions_to_retry as e:
               last_exception = e
               if attempt == max_retries:
                   break
               delay = base_delay * (backoff_factor ** attempt)
               if jitter > 0:
                   delay += random.uniform(0, jitter)
               time.sleep(delay)
       raise last_exception
   ```
   *Self-Correction/Refinement on retry.py*: The prompt says "Retry logic with exponential backoff". The above is standard and robust. I'll keep it clean. Maybe simplify parameters to match typical usage, but the above is fine. I'll stick to a straightforward implementation.

   *`queue/__init__.py`*:
   ```python
   from .core import Job, JobQueue
   from .priority import PriorityQueue
   from .retry import process_with_retry

   __all__ = ["Job", "JobQueue", "PriorityQueue", "process_with_retry"]
   ```
   Wait, the prompt says `__init__.py` should export `JobQueue, Job`. I'll follow that exactly, but it's common practice to export everything. I'll stick to the prompt: `__all__ = ["Job", "JobQueue"]`. I can add the others if needed, but I'll follow the prompt strictly. Actually, I'll export all for usability, but note the prompt's requirement. I'll just export `Job` and `JobQueue` as requested, or maybe include the others for completeness. I'll stick to `__all__ = ["Job", "JobQueue"]` as specified.

5.  **Final Review against Requirements:**
   - *Maintain all existing functionality*: Yes, `Job`, `JobQueue`, `PriorityQueue`, `process_with_retry` are all present.
   - *Proper imports between modules*: `priority.py` imports `Job` from `.core`. `__init__.py` imports from submodules. No circular imports.
   - *Clean public API in __init__.py*: Exports `Job` and `JobQueue` as requested. I'll add `PriorityQueue` and `process_with_retry` to `__init__.py` for a complete package, but I'll make sure the explicit requirement is met. Actually, the prompt says `# Exports: JobQueue, Job`, so I'll just do that.
   - *Each module has a single responsibility*: `core.py` (data model & basic queue), `priority.py` (priority ordering), `retry.py` (retry/backoff logic), `__init__.py` (package API). Perfect.

   Let's write out the code carefully. I'll add type hints and docstrings for professionalism. I'll ensure the structure matches exactly.

   One minor thing: `PriorityQueue` might be expected to inherit from `JobQueue` in some designs, but it's fine as standalone. I'll keep it standalone to avoid state duplication. I'll make sure the interface matches `JobQueue` exactly.

   Let's draft the final response.
   Structure:
   ```
   queue/
   ├── __init__.py
   ├── core.py
   ├── priority.py
   └── retry.py
   ```
   Content matches the refined drafts.
   I'll verify imports: `from .core import Job, JobQueue` in `priority.py` and `__init__.py`. `from .core import Job` in `priority.py`. All good.
   I'll add a brief explanation of the design choices.
   Ready.✅
   Output matches the response. 
   Self-Correction/Verification during thought:
   - Should `PriorityQueue` inherit from `JobQueue`? The prompt says "Priority queue implementation". It's often better to keep them separate or use composition. I'll stick to separate classes with identical interfaces for flexibility.
   - `process_with_retry` signature: I'll make it simple and focused on the requirement.
   - `__init__.py`: I'll explicitly export `Job` and `JobQueue` as requested, but I'll also import the others for convenience, or just follow exactly. I'll follow exactly: `__all__ = ["Job", "JobQueue"]`.
   - I'll add type hints and docstrings to make it production-ready.
   - All requirements met.

   Proceed. 
   Output generation. 
   [Done] 
   *Self-Correction/Note during generation prep*: 
   I should make sure the code blocks are clearly labeled with file paths. I'll present them exactly as requested. I'll also ensure that `PriorityQueue` can be used interchangeably with `JobQueue` by matching the interface. The retry function will be standalone. Everything looks solid.✅
   Output matches the final response. 
   [Proceeds]

</reasoning_content>

<content>
Here's the refactored package structure with clean separation of concerns, proper imports, and type hints for maintainability.

### `queue/__init__.py`
```python
"""Job Queue Package"""

from .core import Job, JobQueue

# Explicit public API as requested
__all__ = ["Job", "JobQueue"]
```

### `queue/core.py`
```python
"""Core data model and basic FIFO queue operations."""

from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, List, Optional


@dataclass
class Job:
    """Represents a unit of work to be processed."""
    id: str
    payload: Any
    status: str = "pending"
    created_at: datetime = field(default_factory=datetime.now)
    retry_count: int = 0


class JobQueue:
    """Basic FIFO queue implementation for Job objects."""
    
    def __init__(self) -> None:
        self._queue: List[Job] = []

    def enqueue(self, job: Job) -> None:
        """Add a job to the back of the queue."""
        self._queue.append(job)

    def dequeue(self) -> Optional[Job]:
        """Remove and return the job at the front of the queue."""
        if self.is_empty():
            return None
        return self._queue.pop(0)

    def peek(self) -> Optional[Job]:
        """Return the job at the front without removing it."""
        if self.is_empty():
            return None
        return self._queue[0]

    def is_empty(self) -> bool:
        """Check if the queue is empty."""
        return len(self._queue) == 0

    def size(self) -> int:
        """Return the number of jobs in the queue."""
        return len(self._queue)
```

### `queue/priority.py`
```python
"""Priority queue implementation using a binary heap."""

import heapq
from typing import Optional

from .core import Job


class PriorityQueue:
    """Priority queue that orders jobs by a numeric priority (lower = higher priority)."""
    
    def __init__(self) -> None:
        self._heap: list = []
        self._counter: int = 0  # Ensures stable ordering for equal priorities

    def enqueue(self, job: Job, priority: int = 0) -> None:
        """Add a job with a given priority."""
        entry = (priority, self._counter, job)
        self._counter += 1
        heapq.heappush(self._heap, entry)

    def dequeue(self) -> Optional[Job]:
        """Remove and return the highest priority job."""
        if self.is_empty():
            return None
        _, _, job = heapq.heappop(self._heap)
        return job

    def peek(self) -> Optional[Job]:
        """Return the highest priority job without removing it."""
        if self.is_empty():
            return None
        return self._heap[0][2]

    def is_empty(self) -> bool:
        """Check if the queue is empty."""
        return len(self._heap) == 0

    def size(self) -> int:
        """Return the number of jobs in the queue."""
        return len(self._heap)
```

### `queue/retry.py`
```python
"""Retry logic with exponential backoff and jitter."""

import random
import time
from typing import Any, Callable, Tuple, Type, Optional


def process_with_retry(
    func: Callable[..., Any],
    *args,
    max_retries: int = 3,
    base_delay: float = 1.0,
    backoff_factor: float = 2.0,
    jitter: float = 0.0,
    exceptions_to_retry: Tuple[Type[Exception], ...] = (Exception,),
    **kwargs,
) -> Any:
    """
    Execute a function with exponential backoff retry logic.
    
    Args:
        func: The callable to execute.
        *args, **kwargs: Arguments passed to the callable.
        max_retries: Maximum number of retry attempts.
        base_delay: Initial delay in seconds.
        backoff_factor: Multiplier applied to delay after each retry.
        jitter: Maximum random seconds to add to delay.
        exceptions_to_retry: Tuple of exception types that trigger a retry.
        
    Returns:
        The result of the successful function call.
        
    Raises:
        The last caught exception if max_retries is exceeded.
    """
    last_exception: Optional[Exception] = None

    for attempt in range(max_retries + 1):
        try:
            return func(*args, **kwargs)
        except exceptions_to_retry as e:
            last_exception = e
            if attempt == max_retries:
                break
                
            delay = base_delay * (backoff_factor ** attempt)
            if jitter > 0:
                delay += random.uniform(0, jitter)
                
            time.sleep(delay)
            
    if last_exception is not None:
        raise last_exception
    raise RuntimeError("process_with_retry exited unexpectedly.")
```

### Key Design Choices:
1. **Single Responsibility**: Each file handles exactly one domain concept (`core` = data & basic queue, `priority` = ordering strategy, `retry` = fault tolerance).
2. **Zero Circular Dependencies**: `priority.py` only imports `Job` from `core.py`. `__init__.py` acts as a facade without creating import cycles.
3. **Interface Parity**: `PriorityQueue` mirrors `JobQueue`'s public interface (`enqueue`, `dequeue`, `peek`, `is_empty`, `size`), allowing drop-in replacement in existing code.
4. **Robust Retry Logic**: Includes configurable backoff, jitter (to prevent thundering herd), and explicit exception filtering.
5. **Clean API**: `__init__.py` explicitly controls what's exposed at the package level, following Python packaging best practices.
</content>