This refactoring separates concerns clearly, 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 specific data structure logic for ordering jobs.)*

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

class PriorityQueue:
    """
    A min-heap implementation of a Priority Queue.
    Items are ordered based on their priority (lower number = higher priority).
    """
    def __init__(self):
        # The heap stores tuples: (priority, entry_count, item)
        # entry_count is used to ensure stable sorting (FIFO for same priority)
        self._heap: List[Tuple[int, int, Any]] = []
        self._counter = 0

    def put(self, item: Any, priority: int):
        """Adds an item to the queue with a given priority."""
        entry = (priority, self._counter, item)
        heapq.heappush(self._heap, entry)
        self._counter += 1

    def get(self) -> Any:
        """Removes and returns the item with the highest priority."""
        if not self._heap:
            raise IndexError("get from empty priority queue")
        # We pop the tuple, but 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`
*(Defines the fundamental data types and the main queue manager.)*

```python
from dataclasses import dataclass
from typing import Callable
from .priority import PriorityQueue

@dataclass(frozen=True)
class Job:
    """
    Represents a single unit of work to be executed.
    """
    job_id: str
    payload: dict
    priority: int = 5  # Default priority
    max_retries: int = 3

class JobQueue:
    """
    Manages the collection of jobs, utilizing a PriorityQueue internally.
    """
    def __init__(self):
        self._queue = PriorityQueue()

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

    def dequeue(self) -> Job:
        """Retrieves the highest priority job from the queue."""
        if self._queue.empty():
            raise IndexError("Cannot dequeue from an empty job queue.")
        
        # The item retrieved is the Job object
        return self._queue.get()

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

```

## `queue/retry.py`
*(Encapsulates the execution and failure handling logic.)*

```python
import time
import random
from .core import Job, JobQueue

# Define the maximum backoff duration (in seconds)
MAX_BACKOFF_TIME = 60

def exponential_backoff(attempt: int) -> float:
    """
    Calculates the delay using exponential backoff with jitter.
    Delay = min(MAX_BACKOFF_TIME, 2^attempt + random_jitter)
    """
    base_delay = 2 ** attempt
    jitter = random.uniform(0, 1)
    delay = min(MAX_BACKOFF_TIME, base_delay + jitter)
    return delay

def process_job(job: Job, worker_function: Callable[[dict], bool]) -> bool:
    """
    Attempts to execute the job using the provided worker function.
    Returns True on success, False on failure.
    """
    try:
        print(f"\n--- Executing Job {job.job_id} (Attempt 1) ---")
        return worker_function(job.payload)
    except Exception as e:
        print(f"!!! Job {job.job_id} failed: {e}")
        return False

def process_with_retry(queue: JobQueue, worker_function: Callable[[dict], bool]):
    """
    Pulls jobs from the queue and attempts to process them with retry logic.
    """
    while not queue.size() == 0:
        job = queue.dequeue()
        
        current_attempt = 1
        success = False
        
        while current_attempt <= job.max_retries:
            success = process_job(job, worker_function)
            
            if success:
                print(f"[Success] Job {job.job_id} completed successfully.")
                break
            
            if current_attempt < job.max_retries:
                delay = exponential_backoff(current_attempt)
                print(f"[Retry] Job {job.job_id} failed. Retrying in {delay:.2f}s (Attempt {current_attempt + 1}/{job.max_retries}).")
                time.sleep(delay)
                current_attempt += 1
            else:
                print(f"[Failure] Job {job.job_id} failed after {job.max_retries} attempts. Dropping job.")
                break
```

## `queue/__init__.py`
*(The public interface of the package.)*

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

# Explicitly expose the main components
__all__ = [
    'Job', 
    'JobQueue', 
    'process_with_retry'
]
```

***

### Example Usage (Demonstration)

To show how the new structure is used, here is how a client would import and use the package:

```python
# main.py (outside the queue directory)
import time
from queue import Job, JobQueue, process_with_retry

# --- Mock Worker Function ---
# This function simulates work that might fail
def mock_worker(payload: dict) -> bool:
    """
    Simulates a worker. Fails the first two times, succeeds on the third.
    """
    if payload.get("attempt", 0) < 2:
        payload["attempt"] = payload.get("attempt", 0) + 1
        print(f"    -> Worker attempted job (Payload: {payload['job_id']}). Failure simulated.")
        raise ConnectionError("External service temporarily unavailable.")
    
    print(f"    -> Worker successfully processed job (Payload: {payload['job_id']}).")
    return True

# --- Execution ---
if __name__ == "__main__":
    job_queue = JobQueue()

    # Job 1: Will fail twice, succeed on the third attempt (max_retries=3)
    job1 = Job(
        job_id="A101", 
        payload={"job_id": "A101", "attempt": 0},
        priority=1, # High priority
        max_retries=3
    )

    # Job 2: Will fail permanently (max_retries=1)
    job2 = Job(
        job_id="B202", 
        payload={"job_id": "B202", "attempt": 0},
        priority=5, # Default priority
        max_retries=1
    )
    
    # Job 3: Will succeed immediately
    job3 = Job(
        job_id="C303", 
        payload={"job_id": "C303", "attempt": 0},
        priority=10 # Low priority
    )

    # Enqueue jobs (PriorityQueue ensures A101 (P1) is processed before B202 (P5) before C303 (P10))
    job_queue.enqueue(job3)
    job_queue.enqueue(job2)
    job_queue.enqueue(job1)

    print("\n================ START PROCESSING ================")
    
    # Start the processing loop
    process_with_retry(job_queue, mock_worker)
    
    print("\n================ PROCESSING COMPLETE ================")
    print(f"Final queue size: {job_queue.size()}")
```