Here is the refactored package structure. Each module focuses on a specific responsibility while maintaining the functionality of the original monolithic file.

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

### 1. `queue/core.py`
Contains the `Job` dataclass and the basic `JobQueue` (FIFO) implementation.

```python
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Callable, List, Optional

@dataclass
class Job:
    """Represents a single unit of work."""
    id: str
    payload: Any
    priority: int = 0
    status: str = "pending"  # pending, processing, completed, failed
    retry_count: int = 0
    created_at: datetime = field(default_factory=datetime.now)
    updated_at: datetime = field(default_factory=datetime.now)
    task: Optional[Callable] = None  # The actual function to execute

    def mark_processing(self):
        self.status = "processing"
        self.updated_at = datetime.now()

    def mark_completed(self):
        self.status = "completed"
        self.updated_at = datetime.now()

    def mark_failed(self):
        self.status = "failed"
        self.updated_at = datetime.now()

    def increment_retry(self):
        self.retry_count += 1
        self.updated_at = datetime.now()

class JobQueue:
    """A basic FIFO queue for managing jobs."""
    
    def __init__(self):
        self._jobs: List[Job] = []

    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 job at the front of the queue."""
        if self._jobs:
            return self._jobs.pop(0)
        return None

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

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

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

    def get_all(self) -> List[Job]:
        """Return a copy of all jobs in the queue."""
        return self._jobs.copy()
```

### 2. `queue/priority.py`
Contains the heap-based `PriorityQueue` implementation.

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

from .core import Job

class PriorityQueue:
    """A priority queue implementation using a min-heap."""
    
    def __init__(self):
        self._heap: List[Job] = []

    def push(self, job: Job) -> None:
        """Add a job to the priority queue based on priority."""
        # We negate priority because heapq is a min-heap, but we want higher priority to come first
        heapq.heappush(self._heap, (-job.priority, job))

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

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

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

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

    def get_all(self) -> List[Job]:
        """Return a copy of all jobs in the priority queue."""
        return [job for _, job in self._heap]
```

### 3. `queue/retry.py`
Contains the logic for executing jobs with exponential backoff and retry handling.

```python
import time
from typing import Callable, Optional

from .core import Job

def process_with_retry(
    job: Job, 
    max_retries: int = 3, 
    backoff_base: float = 1.0
) -> Optional[str]:
    """
    Executes a job's task with exponential backoff retry logic.
    
    Args:
        job: The Job object containing the task and metadata.
        max_retries: Maximum number of retry attempts.
        backoff_base: Base time for exponential backoff calculation.
        
    Returns:
        The result of the task if successful, or None if max retries exceeded.
    """
    if not job.task:
        raise ValueError("Job does not have an associated task callable.")

    for attempt in range(max_retries + 1):
        try:
            job.mark_processing()
            return job.task()
        except Exception as e:
            if attempt < max_retries:
                job.increment_retry()
                # Exponential backoff: base * (2 ** attempt)
                delay = backoff_base * (2 ** attempt)
                print(f"Job {job.id} failed (attempt {attempt + 1}/{max_retries}). Retrying in {delay}s...")
                time.sleep(delay)
            else:
                job.mark_failed()
                print(f"Job {job.id} failed permanently after {max_retries} attempts.")
                return None
    return None
```

### 4. `queue/__init__.py`
Exposes the public API, making it easy for users to import specific components.

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

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

### Key Refactoring Benefits
1.  **Separation of Concerns**: Data (`Job`), Basic Logic (`JobQueue`), Advanced Logic (`PriorityQueue`), and Side Effects (`process_with_retry`) are isolated.
2.  **Maintainability**: Changes to retry logic won't impact the data structure, and changing the priority algorithm won't affect the retry mechanism.
3.  **Testability**: Each module can be unit tested independently (e.g., testing `PriorityQueue` logic without needing to mock the retry sleep).
4.  **Scalability**: New queue strategies can be added in `priority.py` without cluttering `core.py`.
5.  **Clean API**: Users can import exactly what they need (e.g., `from queue import Job, JobQueue`) without loading unnecessary logic.