<reasoning_content>
Here's a thinking process that leads to the suggested refactoring:

1.  **Analyze the Request:**
    *   **Input:** A conceptual single-file implementation (`queue.py`) containing `Job`, `JobQueue`, `PriorityQueue`, and `process_with_retry`.
    *   **Output:** A multi-file package structure (`queue/` package).
    *   **Target Structure:**
        *   `queue/__init__.py` (Public API)
        *   `queue/core.py` (Job dataclass, basic queue operations)
        *   `queue/retry.py` (Retry logic)
        *   `queue/priority.py` (Priority queue implementation)
    *   **Requirements:** Maintain functionality, proper imports, clean API, single responsibility per module.

2.  **Infer the Missing Implementation:**
    *   The prompt gives the *structure* but not the actual *code* of the single-file version. I need to synthesize a reasonable implementation of what `queue.py` likely contained to ensure the refactoring makes sense.
    *   *Assumptions based on typical job queue patterns:*
        *   `Job`: A dataclass holding task ID, payload, status, priority, retry count, etc.
        *   `JobQueue`: A list or deque-based container, adding/removing jobs.
        *   `PriorityQueue`: Likely uses `heapq` to order jobs by priority.
        *   `process_with_retry`: A function that simulates execution, handles failures, and applies backoff logic.
    *   *Goal:* Create code that looks like a real-world refactor, not just stubs.

3.  **Drafting the Modules:**

    *   **`queue/core.py`**:
        *   Needs the `Job` class.
        *   Needs the base `JobQueue` class (FIFO or simple list management).
        *   *Decision:* Let's make `Job` a `@dataclass`. Let `JobQueue` manage the storage.
        *   *Imports:* `dataclasses`, `typing`, `collections.deque`, `uuid`.

    *   **`queue/priority.py`**:
        *   Needs `PriorityQueue`.
        *   Should inherit from or utilize `core.JobQueue` or just implement the heap logic.
        *   *Decision:* Let's have `PriorityQueue` inherit from `JobQueue` to reuse logic, or implement it independently if the prompt implies a specific structure. Given the target structure, `PriorityQueue` usually implies a specific algorithm. Let's make it a wrapper or subclass.
        *   *Refinement:* To keep dependencies clean, `priority.py` should probably import `Job` from `core`. `JobQueue` might be the base, and `PriorityQueue` extends it. Or `JobQueue` is just the container, and `PriorityQueue` is the algorithm. Let's go with `JobQueue` as the base container and `PriorityQueue` as a specialized version.
        *   *Imports:* `heapq`, `core`.

    *   **`queue/retry.py`**:
        *   Needs `process_with_retry`.
        *   Logic: Try to execute, catch exception, calculate delay, retry.
        *   *Imports:* `time`, `core` (for Job status), `random` (maybe for jitter).

    *   **`queue/__init__.py`**:
        *   Exports `Job`, `JobQueue`, `PriorityQueue`, `process_with_retry`.
        *   Imports from submodules.

4.  **Refining the Design (Self-Correction/Edge Case Check):**

    *   *Circular Imports:* If `core` imports `retry` and `retry` imports `core`, that's bad.
    *   *Dependency Flow:*
        *   `core.py`: Defines `Job` and base `JobQueue`. No dependencies on other queue modules.
        *   `priority.py`: Depends on `core` (for `Job`).
        *   `retry.py`: Depends on `core` (for `Job`).
        *   `__init__.py`: Depends on all.
    *   *Public API:* Users should only import from `queue`.
    *   *Functionality:* Ensure `process_with_retry` works conceptually.

5.  **Drafting the Code (Mental or Scratchpad):**

    *   *Core:* Define `Job`. Define `JobQueue`.
    *   *Priority:* Import `heapq`. Define `PriorityQueue`.
    *   *Retry:* Define `process_with_retry`.
    *   *Init:* `from .core import Job, JobQueue`. `from .priority import PriorityQueue`. `from .retry import process_with_retry`.

6.  **Finalizing the Code Structure:**

    *   I need to make sure the code is copy-pasteable and complete.
    *   I will add docstrings and type hints for professionalism.
    *   I will ensure the `__init__.py` makes the package look like a flat module to the user.

7.  **Constructing the Response:**
    *   Present the directory tree first.
    *   Present the content of each file clearly.
    *   Add a brief explanation of the changes made (why this structure is better).

    *(Self-Correction during drafting)*: I should ensure `process_with_retry` is robust. It needs to return the result or raise the exception after max retries. I'll implement a simple simulation.

    *(Refinement on `JobQueue` vs `PriorityQueue`)*: To make the split logical, `JobQueue` should handle the generic FIFO storage/management, while `PriorityQueue` overrides the retrieval logic to use a heap.

    *(Refinement on Imports)*: Use relative imports (e.g., `from .core import Job`) for internal module dependencies.

8.  **Final Review against Constraints:**
    *   Single responsibility? Yes.
    *   Proper imports? Yes (relative).
    *   Clean API? Yes (only public classes/functions in `__init__`).
    *   Functionality maintained? Yes (simulated logic).

    Let's write the code.

    *File 1: `core.py`* - Job dataclass, base Queue.
    *File 2: `priority.py`* - Heap-based priority queue.
    *File 3: `retry.py`* - Retry logic.
    *File 4: `__init__.py`* - Exports.

    *Wait, one detail:* The prompt asks to "Refactor the monolithic job queue". Since I don't have the *original* code, I must reconstruct a plausible original implementation to demonstrate the split. I will create a robust, standard implementation that represents what the original likely was.

    Let's proceed.

    *Wait, `Job` in `core`.*
    *Wait, `JobQueue` in `core`.*
    *Wait, `PriorityQueue` in `priority`.*
    *Wait, `process_with_retry` in `retry`.*

    Looks good. I will write the code now.

    *Check:* Should `JobQueue` be abstract? Let's keep it simple but functional.
    *Check:* Should `process_with_retry` take a function and a job? Yes.

    Let's assemble.

    *(Final thought)*: Make sure to explicitly mention that `core.py` is the base, as `priority.py` depends on `core.py`.

    Okay, ready to generate output.

    *Structure:*
    1. Directory tree.
    2. `queue/__init__.py`
    3. `queue/core.py`
    4. `queue/priority.py`
    5. `queue/retry.py`
    6. Usage example (optional but helpful).

    Let's stick to the requested file contents primarily.

    *Correction:* `JobQueue` usually implies FIFO. `PriorityQueue` implies ordering. I will implement `JobQueue` as a simple FIFO list/deque and `PriorityQueue` as a heap wrapper. This clarifies the separation of concerns.

    Let's write it.

</reasoning_content>

<content>
Here is the refactored package structure. I have reconstructed the underlying logic based on standard job queue patterns to ensure the split is logical and the functionality is preserved.

### Directory Structure

```text
queue/
├── __init__.py
├── core.py
├── priority.py
└── retry.py
```

### 1. `queue/__init__.py`
This file exposes the clean public API. Users of this package import directly from here.

```python
from .core import Job, JobQueue
from .priority import PriorityQueue
from .retry import process_with_retry

__all__ = [
    "Job",
    "JobQueue", 
    "PriorityQueue",
    "process_with_retry"
]
```

### 2. `queue/core.py`
Contains the data model (`Job`) and the base container logic (`JobQueue`).

```python
import uuid
from dataclasses import dataclass, field
from typing import Any, Deque, List, Optional
from collections import deque


@dataclass
class Job:
    """Represents a task to be processed."""
    id: str = field(default_factory=lambda: str(uuid.uuid4()))
    payload: Any = None
    status: str = "pending"
    priority: int = 0
    retry_count: int = 0
    max_retries: int = 3
    created_at: str = field(default_factory=lambda: "now") 

    def is_done(self) -> bool:
        return self.status in ["completed", "failed"]


class JobQueue:
    """Base FIFO queue implementation for managing job storage."""

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

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

    def dequeue(self) -> Optional[Job]:
        """Remove and return the oldest job from the queue."""
        if self._jobs:
            return self._jobs.popleft()
        return None

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

    def is_empty(self) -> bool:
        """Check if the queue has no jobs."""
        return len(self._jobs) == 0

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

### 3. `queue/priority.py`
Handles the heap-based logic for retrieving jobs based on priority.

```python
import heapq
from typing import List, Optional

from .core import Job, JobQueue


class PriorityQueue(JobQueue):
    """Priority queue implementation using a min-heap."""

    def __init__(self):
        super().__init__()
        self._heap: List[tuple] = []

    def enqueue(self, job: Job) -> None:
        """Add a job to the queue based on priority (lower number = higher priority)."""
        # We store (-priority, timestamp, job) to ensure stable sort if priorities match
        # and to invert priority for min-heap behavior (higher priority number = higher rank)
        # Assuming higher integer = higher priority, we negate it.
        entry = (-job.priority, job.id, job)
        heapq.heappush(self._heap, entry)

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

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

    def is_empty(self) -> bool:
        """Check if the queue has no jobs."""
        return len(self._heap) == 0
```

### 4. `queue/retry.py`
Contains the logic for handling execution failures and backoff strategies.

```python
import random
import time
from typing import Callable, Any

from .core import Job


def process_with_retry(
    job: Job, 
    func: Callable[[Job], Any], 
    max_retries: int = None,
    base_delay: float = 1.0,
    max_delay: float = 60.0
) -> Any:
    """
    Executes a function with a job payload, applying exponential backoff on failure.
    
    Args:
        job: The job object containing payload and state.
        func: The function to execute with the job.
        max_retries: Maximum retry attempts.
        base_delay: Initial delay in seconds.
        max_delay: Maximum delay cap.
    
    Returns:
        The result of the function if successful.
    
    Raises:
        Exception: If max retries exceeded.
    """
    retries = max_retries if max_retries is not None else job.max_retries
    
    for attempt in range(retries + 1):
        try:
            return func(job)
        except Exception as e:
            job.retry_count += 1
            job.status = "failed"
            
            if attempt < retries:
                # Exponential backoff with jitter
                delay = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay)
                time.sleep(delay)
            else:
                raise e
```

### Refactoring Notes

1.  **Single Responsibility**: 
    *   `core.py` handles data structures and basic storage.
    *   `priority.py` handles ordering logic (heap).
    *   `retry.py` handles execution strategy and timing.
2.  **Dependency Flow**: 
    *   `priority.py` and `retry.py` import from `core.py`.
    *   `__init__.py` imports from all submodules.
    *   There are no circular dependencies.
3.  **Public API**: 
    *   The consumer of the package only needs to import from `queue`. They do not need to know the internal file structure.
4.  **Extensibility**: 
    *   You can now add a `log.py` or `monitoring.py` module later without touching the core logic, as dependencies are managed cleanly.
</content>