This refactoring splits the concerns into specialized modules, making the code easier to test, maintain, and scale.

Here is the content for each file in the `queue/` directory.

***

## 📁 `queue/priority.py`
*(Handles the underlying mechanism for ordering jobs.)*

```python
import heapq
from typing import List, Tuple, Any

class PriorityQueue:
    """
    Implements a min-heap based priority queue.
    Items are stored as (priority, insertion_order, item).
    """
    def __init__(self):
        # The heap stores tuples: (priority, count, item)
        self._queue: List[Tuple[int, int, Any]] = []
        self._counter = 0  # Used to ensure FIFO order for items with the same priority

    def put(self, item: Any, priority: int):
        """Adds an item to the queue with a given priority."""
        # Lower priority number means higher priority (standard min-heap behavior)
        entry = (priority, self._counter, item)
        heapq.heappush(self._queue, entry)
        self._counter += 1

    def get(self) -> Any:
        """Removes and returns the highest priority item."""
        if not self.empty():
            # Pop the root item (which has the lowest priority number)
            priority, count, item = heapq.heappop(self._queue)
            return item
        raise IndexError("get from empty priority queue")

    def empty(self) -> bool:
        """Checks if the queue is empty."""
        return not self._queue

    def qsize(self) -> int:
        """Returns the number of items in the queue."""
        return len(self._queue)
```

## 📁 `queue/core.py`
*(Defines the job structure and the primary queue manager.)*

```python
from typing import Any
from dataclasses import dataclass
from queue.priority import PriorityQueue

@dataclass(frozen=True)
class Job:
    """Represents a single unit of work."""
    task_id: str
    payload: Any
    priority: int = 0
    max_retries: int = 3
    attempt_count: int = 0

    def __repr__(self):
        return f"Job(id={self.task_id}, priority={self.priority}, attempts={self.attempt_count})"

class JobQueue:
    """
    The main queue manager responsible for holding and retrieving jobs.
    It utilizes a PriorityQueue internally.
    """
    def __init__(self):
        self._queue = PriorityQueue()

    def enqueue(self, job: Job):
        """Adds a job to the queue."""
        # We use the Job's priority for the queue's ordering
        self._queue.put(job, job.priority)
        print(f"[Queue] Enqueued job: {job.task_id} (Priority: {job.priority})")

    def dequeue(self) -> Job:
        """Removes and returns the highest priority job."""
        try:
            job = self._queue.get()
            print(f"[Queue] Dequeued job: {job.task_id}")
            return job
        except IndexError as e:
            print(f"[Queue] Error: {e}")
            raise

    def is_empty(self) -> bool:
        """Checks if the queue is empty."""
        return self._queue.empty()

    def size(self) -> int:
        """Returns the current size of the queue."""
        return self._queue.qsize()
```

## 📁 `queue/retry.py`
*(Handles the execution logic, specifically retry and backoff.)*

```python
import time
import random
from queue.core import Job

def execute_task(job: Job) -> bool:
    """
    Simulates the actual execution of the task.
    Returns True on success, False on failure.
    """
    print(f"--- Executing task {job.task_id} (Attempt {job.attempt_count + 1})...")
    
    # Simulate failure 70% of the time on the first attempt
    if job.attempt_count == 0 and random.random() < 0.7:
        print(f"--- Task {job.task_id} failed.")
        return False
    
    # Simulate success
    print(f"+++ Task {job.task_id} succeeded.")
    return True


def process_with_retry(job: Job, queue_manager) -> bool:
    """
    Attempts to execute a job, implementing exponential backoff and retries.
    
    If the job fails and retries remain, it is re-enqueued.
    """
    while job.attempt_count < job.max_retries:
        
        if execute_task(job):
            # Success!
            return True
        
        # Failure occurred. Increment attempt count.
        job.attempt_count += 1
        
        if job.attempt_count >= job.max_retries:
            print(f"!!! Job {job.task_id} failed permanently after {job.max_retries} attempts.")
            return False # Permanent failure

        # Calculate exponential backoff: 2^attempt * jitter
        backoff_time = (2 ** job.attempt_count) + random.uniform(0, 1)
        print(f"-> Retrying {job.task_id} in {backoff_time:.2f} seconds...")
        time.sleep(0.1) # Use a short sleep for demonstration
        
        # Re-enqueue the job with updated attempt count
        queue_manager.enqueue(job)
        return True # Hand off to the queue to be picked up later
        
    return False # Should not be reached if logic is correct
```

## 📁 `queue/__init__.py`
*(The public API entry point for the package.)*

```python
# Expose the core components for easy access
from .core import Job, JobQueue
from .retry import process_with_retry

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

***

## Example Usage (Demonstration)

To show how the new package structure works, here is a simple driver script:

```python
# driver.py (outside the queue/ directory)

from queue import Job, JobQueue, process_with_retry
import time

if __name__ == "__main__":
    
    # 1. Setup
    job_queue = JobQueue()

    # 2. Create jobs
    job1 = Job(task_id="A", payload={"data": 1}, priority=1) # High priority
    job2 = Job(task_id="B", payload={"data": 2}, priority=5) # Low priority
    job3 = Job(task_id="C", payload={"data": 3}, priority=3, max_retries=2) # Medium priority, limited retries

    # 3. Enqueue
    job_queue.enqueue(job1)
    job_queue.enqueue(job2)
    job_queue.enqueue(job3)

    print("\n--- Starting processing loop ---\n")

    # 4. Processing Loop
    while not job_queue.is_empty():
        
        # Dequeue the highest priority job
        job_to_process = job_queue.dequeue()
        
        # Process it using the retry logic
        success = process_with_retry(job_to_process, job_queue)

        if success:
            print(f"\n[Main] Job {job_to_process.task_id} finished successfully or is scheduled for later.")
        else:
            print(f"\n[Main] Job {job_to_process.task_id} failed permanently.")
        
        time.sleep(0.5) # Pause between processing cycles
```