This refactoring separates concerns cleanly, making the code easier to test, maintain, and scale.

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

***

## 📁 `queue/priority.py`
*(Single Responsibility: Implementing the priority queue logic.)*

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

class PriorityQueue:
    """
    A min-heap implementation of a Priority Queue.
    Items are stored as (priority, insertion_index, item).
    """
    def __init__(self):
        # The heap stores tuples: (priority, counter, item)
        self._heap: List[Tuple[int, int, Any]] = []
        self._counter = 0  # Tie-breaker for stable ordering

    def push(self, item: Any, priority: int):
        """Adds an item to the queue with a specified priority."""
        # Lower priority number means higher urgency
        entry = (priority, self._counter, item)
        heapq.heappush(self._heap, entry)
        self._counter += 1

    def pop(self) -> Any:
        """Removes and returns the item with the highest priority (lowest priority number)."""
        if not self._heap:
            raise IndexError("pop from empty priority queue")
        # We only return the actual item (index 2)
        return heapq.heappop(self._heap)[2]

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

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

## 📁 `queue/core.py`
*(Single Responsibility: Defining the Job structure and the main queue interface.)*

```python
from typing import Callable, Any
from .priority import PriorityQueue

class Job:
    """
    Represents a single unit of work.
    """
    def __init__(self, task: Callable[[], Any], priority: int = 0, job_id: str = None):
        self.task = task
        self.priority = priority
        self.job_id = job_id if job_id is not None else str(hash(task))
        self.attempts = 0

    def __repr__(self):
        return f"<Job id={self.job_id} priority={self.priority} attempts={self.attempts}>"

class JobQueue:
    """
    The primary interface for managing and retrieving jobs.
    Uses PriorityQueue internally.
    """
    def __init__(self):
        self._queue = PriorityQueue()

    def enqueue(self, job: Job):
        """Adds a job to the queue."""
        self._queue.push(job, job.priority)
        print(f"[Queue] Enqueued job {job.job_id} with priority {job.priority}.")

    def dequeue(self) -> Job:
        """Retrieves and removes the highest priority job."""
        if self._queue.empty():
            raise IndexError("Cannot dequeue from an empty queue.")
        job = self._queue.pop()
        print(f"[Queue] Dequeued job {job.job_id}.")
        return job

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

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

## 📁 `queue/retry.py`
*(Single Responsibility: Handling the execution logic and retry mechanism.)*

```python
import time
from typing import Callable, Any
from .core import Job

def execute_job(job: Job) -> Any:
    """
    Executes the task defined in the job.
    """
    try:
        print(f"--- Executing job {job.job_id} (Attempt {job.attempts + 1}) ---")
        result = job.task()
        print(f"--- Job {job.job_id} completed successfully. ---")
        return result
    except Exception as e:
        print(f"!!! Job {job.job_id} failed: {e}")
        raise e

def process_with_retry(job: Job, max_retries: int = 3, initial_delay: float = 1.0) -> Any:
    """
    Executes a job, applying exponential backoff upon failure.

    :param job: The Job object to execute.
    :param max_retries: Maximum number of times to attempt execution.
    :param initial_delay: Starting delay in seconds.
    :return: The result of the successful job execution.
    :raises Exception: If the job fails after all retry attempts.
    """
    job.attempts = 0
    while job.attempts < max_retries:
        try:
            return execute_job(job)
        except Exception as e:
            job.attempts += 1
            if job.attempts >= max_retries:
                print(f"!!! Job {job.job_id} failed permanently after {max_retries} attempts.")
                raise e

            # Calculate exponential backoff delay
            delay = initial_delay * (2 ** (job.attempts - 1))
            print(f"--- Retrying job {job.job_id} in {delay:.2f} seconds... ---")
            time.sleep(delay)

    # Should be unreachable if logic is correct, but useful for safety
    raise RuntimeError("Processing loop exited unexpectedly.")
```

## 📁 `queue/__init__.py`
*(Single Responsibility: Defining the public API for the package.)*

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

# Public API exposure
__all__ = ["Job", "JobQueue", "process_with_retry"]
```

***

### Usage Example (Demonstrates the API)

To show how this works, here is a simple test script outside the `queue` directory:

```python
# main.py
import time
from queue import Job, JobQueue, process_with_retry

# --- Setup ---
queue_manager = JobQueue()

# --- Task Definitions ---

# A task that always succeeds
def simple_task():
    return "Task Completed Successfully"

# A task that fails twice before succeeding
fail_count = 0
def flaky_task():
    global fail_count
    fail_count += 1
    if fail_count < 3:
        raise ConnectionError("Simulated network failure.")
    return "Flaky Task Succeeded!"

# A task that always fails
def critical_task():
    raise ValueError("Critical failure detected.")

# --- Enqueuing Jobs ---

# 1. Standard successful job
job1 = Job(task=simple_task, priority=10, job_id="J1_Simple")
queue_manager.enqueue(job1)

# 2. Flaky job (needs 3 attempts)
job2 = Job(task=flaky_task, priority=5, job_id="J2_Flaky")
queue_manager.enqueue(job2)

# 3. Guaranteed failure job
job3 = Job(task=critical_task, priority=1, job_id="J3_Critical")
queue_manager.enqueue(job3)


# --- Processing Loop ---
print("\n=====================================")
print("Starting Job Processing...")
print("=====================================\n")

while not queue_manager.is_empty():
    try:
        job = queue_manager.dequeue()
        
        # Use the retry mechanism for execution
        try:
            result = process_with_retry(job)
            print(f"\n[RESULT] Job {job.job_id} final result: {result}")
        except Exception as e:
            print(f"\n[FAILURE] Job {job.job_id} permanently failed and was dropped.")

    except IndexError as e:
        print(f"Queue is empty. Stopping.")
        break

print("\n=====================================")
print("Processing finished.")
```