<reasoning_content>
Thinking Process:

1.  **Analyze the Request:**
    *   Goal: Extend a job queue with retry logic and exponential backoff.
    *   Requirements:
        1.  Add `process_job(job_id: str, processor: Callable) -> bool` method.
        2.  Retry up to 3 times on exception.
        3.  Exponential backoff: 1s, 2s, 4s (simulated, not necessarily actual `time.sleep`).
        4.  Track retry count for each job.
        5.  Return `True` on success, `False` on exhaustion.
    *   Constraint: Write only Python code, no explanations.
    *   Context: There seems to be an implied existing `JobQueue` class structure (based on `queue.add_job` and `queue.process_job`), though the prompt asks to "Extend the job queue". I need to provide a complete implementation or at least the relevant parts assuming a base structure. Since the prompt implies extending an existing concept but asks for "only the Python code", I should provide a class definition that encompasses the necessary state management and the specific method requested. I'll need to define the `JobQueue` class with an `add_job` method (implied by the example) and the new `process_job` method.

2.  **Determine Class Structure:**
    *   Class `JobQueue`.
    *   Needs storage for jobs (likely a dictionary mapping `job_id` to job data/state).
    *   Needs `add_job` method (implied by example).
    *   Needs `process_job` method (explicitly requested).
    *   Needs logic for retries (max 3 attempts).
    *   Needs logic for backoff (1s, 2s, 4s).
    *   Needs tracking of retry counts per job.

3.  **Drafting the Code:**
    *   *Imports:* `Callable`, `List`, `Dict`, `Any` (standard typing).
    *   *Class `JobQueue`:*
        *   `__init__`: Initialize job storage.
        *   `add_job`: Store job data.
        *   `process_job`: Implement the logic.
    *   *Retry Logic:*
        *   Max retries = 3 (meaning 1 initial + 3 retries = 4 attempts total? Or 3 attempts total? Usually "retry up to 3 times" means if it fails, try again, up to 3 more times. However, standard interpretation often aligns with `max_attempts = 3`. Let's look at the example backoff: 1s, 2s, 4s. This implies 3 retry intervals. So 1 initial attempt + 3 retries = 4 total attempts. Or does it mean 3 total attempts? "Retry up to 3 times" usually means `retry_count` goes 1, 2, 3.
        *   Let's interpret "Retry up to 3 times" as: Attempt 1 -> Fail -> Retry 1 (wait 1s) -> Fail -> Retry 2 (wait 2s) -> Fail -> Retry 3 (wait 4s) -> Fail -> Stop. Total 4 attempts.
        *   However, often "retry up to N times" implies N total attempts including the first one in some contexts, but strictly linguistically "retry" means "do again". So 1 initial + 3 retries = 4 calls.
        *   Let's check the backoff list: 1s, 2s, 4s. That's 3 values. This supports the 3 retries interpretation.
        *   Wait, the requirement says "Track retry count for each job". This implies the state needs to persist or be tracked during the `process_job` call. Since `process_job` is called immediately in the example, the state might be transient within that call or stored in the queue. Given `process_job` takes a `job_id`, it likely retrieves the job, processes it, and updates state.
        *   Let's assume the job data needs to store `retry_count`.
    *   *Backoff:* `delays = [1, 2, 4]`.
    *   *Return:* `True` if success, `False` if all retries exhausted.

4.  **Refining Logic:**
    *   Store jobs in a dictionary: `self.jobs = {}`.
    *   `add_job(job_id, data)`: `self.jobs[job_id] = {"data": data, "retry_count": 0}`.
    *   `process_job(job_id, processor)`:
        *   Get job.
        *   Loop max 3 retries (plus initial attempt).
        *   Try calling `processor`.
        *   If success, return `True`.
        *   If exception:
            *   Increment retry count.
            *   If retry count <= 3:
                *   Wait (store delay).
                *   Continue loop.
            *   Else:
                *   Return `False`.
    *   Wait, the requirement says "Track retry count for each job". This implies the `JobQueue` instance should maintain this state across calls or within the `process_job` invocation if it's a stateful queue. Given the example calls `process_job` directly, I will store the retry count in the job metadata within the queue.

5.  **Handling the Backoff:**
    *   The prompt says: "The backoff delays can be stored/tracked rather than actually sleeping."
    *   So I can store the delay in the job dict or just calculate it inside the method. Storing it in the job dict makes it persistent if `process_job` is called multiple times for the same job ID (though the example implies a single call). I'll calculate it based on the retry attempt number.
    *   Delays: 1, 2, 4.
    *   Attempt 0 (Initial): No wait.
    *   Attempt 1 (Retry 1): Wait 1s.
    *   Attempt 2 (Retry 2): Wait 2s.
    *   Attempt 3 (Retry 3): Wait 4s.
    *   Max retries = 3.

6.  **Edge Cases:**
    *   Job ID not found.
    *   Processor raises unexpected types.
    *   Requirement says "If the processor raises an exception".

7.  **Final Code Structure:**
    *   Import `Callable`.
    *   Define `JobQueue` class.
    *   `__init__`
    *   `add_job` (to match example)
    *   `process_job` (core requirement)

    *Self-Correction on "Retry up to 3 times":*
    If I retry 3 times, that means 1 initial + 3 retries = 4 executions.
    The delays are 1s, 2s, 4s.
    Execution 1 -> Fail.
    Wait 1s.
    Execution 2 -> Fail.
    Wait 2s.
    Execution 3 -> Fail.
    Wait 4s.
    Execution 4 -> Fail.
    Stop.
    This matches the 3 delay values provided (1, 2, 4).

    *Wait, "Retry up to 3 times"* could also mean Total Attempts = 3.
    If Total Attempts = 3:
    Exec 1 -> Fail.
    Wait 1s.
    Exec 2 -> Fail.
    Wait 2s.
    Exec 3 -> Fail.
    Stop.
    This uses only 2 delays (1, 2). But requirement lists 1, 2, 4.
    So it must be 1 Initial + 3 Retries = 4 Attempts.
    Retries 1, 2, 3 correspond to delays 1, 2, 4.

    *Tracking:* I will store `retry_count` in the job dictionary.

    *Code:*
    ```python
    from typing import Callable, Dict, Any

    class JobQueue:
        def __init__(self):
            self.jobs: Dict[str, Any] = {}

        def add_job(self, job_id: str, data: Any) -> None:
            self.jobs[job_id] = {
                "data": data,
                "retry_count": 0
            }

        def process_job(self, job_id: str, processor: Callable) -> bool:
            if job_id not in self.jobs:
                return False

            job = self.jobs[job_id]
            max_retries = 3
            backoff_delays = [1, 2, 4]
            
            # Attempt 1 (Initial)
            # If we consider "retry up to 3 times" as 3 additional attempts after the first
            # Then we have 4 total attempts.
            # Retries 1, 2, 3 map to delays 0, 1, 2 in the backoff list?
            # Or retries 1, 2, 3 map to delays 1, 2, 4.
            
            # Let's implement a loop.
            # Current attempt logic:
            # We start with attempt 0.
            # If fail, we increment retry_count.
            # If retry_count <= max_retries:
            #    wait backoff[retry_count - 1]
            #    retry
            
            # Let's trace:
            # Try 1. Fail. retry_count becomes 1.
            # Wait 1s (index 0).
            # Try 2. Fail. retry_count becomes 2.
            # Wait 2s (index 1).
            # Try 3. Fail. retry_count becomes 3.
            # Wait 4s (index 2).
            # Try 4. Fail. retry_count becomes 4.
            # Stop.
            
            # This aligns with "Retry up to 3 times" (1, 2, 3) and delays [1, 2, 4].
            
            for attempt in range(max_retries + 1):
                try:
                    processor(job["data"])
                    return True
                except Exception:
                    job["retry_count"] = attempt
                    if attempt < max_retries:
                        # Simulate backoff
                        delay = backoff_delays[attempt]
                        # In a real scenario: time.sleep(delay)
                        # Requirement: "stored/tracked rather than actually sleeping"
                        # I'll just note the delay logic or store it.
                        # I will store the delay in the job state to satisfy "backoff delays can be stored/tracked"
                        job["last_backoff"] = delay
                    else:
                        return False
            
            return False
    ```
    Wait, `job["retry_count"]` update logic inside the loop needs to be careful.
    If I update `retry_count` to `attempt` (0, 1, 2, 3), then after the last attempt (4), `retry_count` is 3? No, `range(4)` is 0,1,2,3.
    If I want to track how many *retries* were made:
    Initial attempt = 0 retries.
    First retry = 1 retry.
    ...
    Third retry = 3 retries.
    
    My loop `range(max_retries + 1)` covers 0, 1, 2, 3.
    If `attempt` is 0: Initial.
    If `attempt` is 1: First retry.
    If `attempt` is 2: Second retry.
    If `attempt` is 3: Third retry.
    
    If I fail on `attempt` 3 (the 4th execution):
    I increment retry count?
    The requirement says "Track retry count for each job".
    Usually, `retry_count` represents how many times it has been retried.
    So if it succeeds on attempt 1, retry count is 0.
    If it fails, retries, and succeeds on attempt 2, retry count is 1.
    
    Revised loop:
    ```python
    retry_count = 0
    while True:
        try:
            processor(...)
            return True
        except:
            if retry_count < max_retries:
                delay = backoff_delays[retry_count]
                job["retry_count"] = retry_count
                # sleep(delay)
                retry_count += 1
                continue
            else:
                job["retry_count"] = retry_count
                return False
    ```
    Wait, `backoff_delays` has 3 items [1, 2, 4].
    If `retry_count` is 0 (first retry): delay = 1.
    If `retry_count` is 1 (second retry): delay = 2.
    If `retry_count` is 2 (third retry): delay = 4.
    If `retry_count` is 3 (stop): No delay, just return False.
    This matches "Retry up to 3 times" (0, 1, 2 indices) with delays [1, 2, 4].
    
    Let's refine the variable naming to ensure clarity.
    The prompt asks for "Track retry count for each job". I should update `self.jobs[job_id]["retry_count"]`.
    
    Also, `add_job` is required by the example code provided (`queue.add_job(...)`).
    
    One detail: "The backoff delays can be stored/tracked rather than actually sleeping."
    I can store the calculated delay in the job dict for observability, though strictly speaking, just calculating it is enough. I will add a field `last_backoff_delay` to demonstrate tracking.

    Final check on constraints:
    1. Add `process_job`.
    2. Retry up to 3 times.
    3. Exponential backoff 1s, 2s, 4s.
    4. Track retry count.
    5. Return bool.
    6. Only Python code.

    I will write the complete class definition to ensure it runs standalone based on the example.

    Wait, one nuance: `process_job` signature `process_job(job_id: str, processor: Callable) -> bool`.
    The example shows `queue.process_job("job1", fetch_url)`.
    `fetch_url` takes `data`.
    So `processor` should be called with `job["data"]`.
    
    Wait, in the example:
    ```python
    def fetch_url(data):
        return requests.get(data["url"])
    ```
    `queue.add_job("job1", {"url": "..."})`
    So `add_job` stores `data`. `process_job` calls `processor(data)`.
    
    Okay, ready to write.

    Wait, one more check on "Retry up to 3 times".
    Does it mean:
    Attempt 1 (0 retries)
    Attempt 2 (1 retry)
    Attempt 3 (2 retries)
    Attempt 4 (3 retries)
    Total 4 attempts.
    Delays:
    Between 1 & 2: 1s
    Between 2 & 3: 2s
    Between 3 & 4: 4s
    This requires 3 delay values.
    My logic:
    Loop 0 to 3 (4 iterations).
    Inside loop, if fail:
      If retry_count < 3:
         Wait backoff[retry_count]
         retry_count += 1
         continue
      Else:
         return False
    
    Iteration 0:
      Fail. retry_count = 0. < 3. Wait 1s. retry_count -> 1.
    Iteration 1:
      Fail. retry_count = 1. < 3. Wait 2s. retry_count -> 2.
    Iteration 2:
      Fail. retry_count = 2. < 3. Wait 4s. retry_count -> 3.
    Iteration 3:
      Fail. retry_count = 3. Not < 3. Return False.
      
    This works perfectly with the provided delays [1, 2, 4].
    
    Wait, I need to make sure I update the job's retry count correctly.
    If I succeed on Iteration 1 (Retry 1), `retry_count` should be 1.
    If I succeed on Iteration 0, `retry_count` should be 0.
    So I should update `job["retry_count"]` *after* the delay logic but before the next loop?
    Or just store the current attempt number as the retry count.
    Actually, `retry_count` should represent how many retries happened *before* success.
    So if I succeed on the first try, `retry_count` is 0.
    If I fail first, retry second, succeed, `retry_count` is 1.
    
    So:
    ```python
    retry_count = 0
    while retry_count <= max_retries:
       try:
          processor(...)
          job["retry_count"] = retry_count
          return True
       except:
          if retry_count < max_retries:
             delay = backoff_delays[retry_count]
             job["retry_count"] = retry_count # Or save the fact that we are retrying
             # Simulate sleep
             retry_count += 1
          else:
             job["retry_count"] = retry_count
             return False
    ```
    Wait, `retry_count` in the job object should reflect the final state.
    If it succeeds on the 2nd attempt (1 retry), `retry_count` = 1.
    If it fails all, `retry_count` = 3 (since max retries = 3).
    
    Let's refine the loop to ensure `job["retry_count"]` is accurate.
    
    ```python
    retries = 0
    while True:
        try:
            processor(job["data"])
            job["retry_count"] = retries
            return True
        except Exception:
            if retries < 3:
                delay = backoff_delays[retries]
                job["retry_count"] = retries # Marking current retry count before proceeding
                # time.sleep(delay)
                retries += 1
            else:
                job["retry_count"] = retries
                return False
    ```
    Wait, if I succeed on the 2nd try, `retries` was 1 when the exception was caught previously?
    No.
    Start: retries = 0.
    Try 1. Fail.
    retries < 3. delay = backoff[0]. retries -> 1.
    Try 2. Success.
    `job["retry_count"] = 1`.
    This means 1 retry happened. Correct.
    
    Try 1. Fail.
    retries = 1.
    Try 2. Fail.
    retries < 3. delay = backoff[1]. retries -> 2.
    Try 3. Success.
    `job["retry_count"] = 2`.
    Correct.
    
    Try 1. Fail.
    retries = 1.
    Try 2. Fail.
    retries = 2.
    Try 3. Fail.
    retries < 3. delay = backoff[2]. retries -> 3.
    Try 4. Fail.
    retries = 3. Not < 3.
    `job["retry_count"] = 3`.
    Return False.
    Correct.

    Wait, in the loop logic above:
    If I succeed, I set `job["retry_count"] = retries`.
    If I fail, I increment `retries`.
    So if I succeed on the second attempt, `retries` is 1. `job["retry_count"]` becomes 1.
    This looks correct.

    One thing: `backoff_delays` has 3 items. Indices 0, 1, 2.
    If `retries` is 0, 1, 2: valid index.
    If `retries` is 3: loop breaks, no index access.
    So `backoff_delays[retries]` is safe inside `if retries < 3`.

    Code structure looks solid. I will omit type hints for brevity if needed, but Python code usually implies standard typing. I will include imports for `Callable`.

    Wait, I should check if `job_id` exists in `self.jobs`. If not, should I return False or raise? Example implies it exists. I'll add a check.

    One detail: "Extend the job queue". I should provide the class code.
    I will assume `add_job` is part of the extension or base. I'll include it to make the code runnable based on the example.

    Final check on "Write only the Python code, no explanations."
    I will output the code block.

    One small detail: `backoff_delays` values are integers (seconds).
    I will store `last_backoff` in the job dict to satisfy "backoff delays can be stored/tracked".

    Code plan:
    1. Import `Callable`.
    2. Define `JobQueue`.
    3. `__init__`: `self.jobs = {}`.
    4. `add_job`: `self.jobs[job_id] = {"data": data, "retry_count": 0}`.
    5. `process_job`: Implement logic as derived above.

    Wait, `process_job` should update the `retry_count` in the stored job dict so it persists if `process_job` is called again? The example implies a one-shot processing. But "Track retry count for each job" implies state management. Storing it in `self.jobs` is the way to go.

    Let's write it.

```python
from typing import Callable, Dict, Any

class JobQueue:
    def __init__(self):
        self.jobs: Dict[str, Any] = {}

    def add_job(self, job_id: str, data: Any) -> None:
        self.jobs[job_id] = {
            "data": data,
            "retry_count": 0,
            "last_backoff": None
        }

    def process_job(self, job_id: str, processor: Callable) -> bool:
        if job_id not in self.jobs:
            return False

        job = self.jobs[job_id]
        max_retries = 3
        backoff_delays = [1, 2, 4]
        retries = 0

        while True:
            try:
                processor(job["data"])
                job["retry_count"] = retries
                return True
            except Exception:
                if retries < max_retries:
                    delay = backoff_delays[retries]
                    job["retry_count"] = retries
                    job["last_backoff"] = delay
                    retries += 1
                else:
                    job["retry_count"] = retries
                    return False
```
    Wait, `job["retry_count"]` update in the `except` block before incrementing `retries` sets it to the count *before* the current retry attempt?
    If `retries` is 0 (First retry):
    Fail.
    `job["retry_count"] = 0`.
    `retries` -> 1.
    Next loop.
    If Success:
    `job["retry_count"] = 1`.
    So if it succeeds on the first retry, `retry_count` is 1.
    If it fails the first retry (retries=0), it increments to 1.
    Wait, if it fails on the very first attempt (Initial), `retries` is 0.
    It enters `except`. `retries < 3`. `delay = backoff[0]`. `retries` -> 1.
    Next loop. Success. `job["retry_count"] = 1`.
    This implies 1 retry happened. Correct.
    
    If it fails on the second retry (Initial + 1 retry).
    Loop 1 (Attempt 1). Fail. `retries` -> 1.
    Loop 2 (Attempt 2). Fail. `retries` -> 2.
    Loop 3 (Attempt 3). Fail. `retries` -> 3.
    Loop 4 (Attempt 4). Fail. `retries` is 3. `retries < 3` is False.
    Returns False. `job["retry_count"] = 3`.
    This implies 3 retries happened. Correct.

    Looks good.

    Wait, I should check if `job["data"]` is passed correctly.
    Example: `fetch_url(data)`. `add_job` stores `data`.
    `process_job` calls `processor(job["data"])`.
    Yes.

    One minor thing: `job["retry_count"]` inside the `except` block before incrementing sets it to the count of retries *completed* so far.
    If I fail the first attempt (retries=0), I set `retry_count` to 0.
    Then I increment `retries` to 1.
    If I succeed on the next attempt, I set `retry_count` to 1.
    So if I succeed on the first retry, the stored count is 1.
    If I fail the first retry (and succeed on the second), stored count is 2.
    Wait, if I fail on Initial (Attempt 1), then succeed on Retry 1 (Attempt 2).
    Loop 1: Fail. `retries`=0. Update `job["retry_count"]`=0. Increment `retries`=1.
    Loop 2: Success. `job["retry_count"]`=1.
    Result: 1 retry.
    This seems correct.

    Wait, what if I fail on Initial, Retry 1, Retry 2, and Succeed on Retry 3?
    Loop 1: Fail. `retries`=0. `job["retry_count"]`=0. `retries`->1.
    Loop 2: Fail. `retries`=1. `job["retry_count"]`=1. `retries`->2.
    Loop 3: Fail. `retries`=2. `job["retry_count"]`=2. `retries`->3.
    Loop 4: Success. `job["retry_count"]`=3.
    Result: 3 retries.
    This is correct.

    I will remove the explicit type hints on `__init__` arguments to keep it cleaner, but keep them on `process_job` signature as per requirement `process_job(job_id: str, processor: Callable) -> bool`.

    Wait, I need to make sure I don't use `time.sleep`. The prompt says "can be stored/tracked rather than actually sleeping". I will just track the delay.

    Final check on imports. `Callable` is in `typing`.

    One detail: `job["retry_count"]` update in the `except` block.
    In the loop:
    `except`:
       `if retries < max_retries`:
          `job["retry_count"] = retries`
          `job["last_backoff"] = delay`
          `retries += 1`
    This sets the count to the number of retries *before* the current one?
    No, `retries` is the number of retries *about to happen* (or that happened).
    When `retries` is 0 (Initial attempt), if it fails:
    We are about to do 1st retry.
    `job["retry_count"]` becomes 0?
    Actually, `retry_count` usually means "how many times we have retried".
    If we succeed on the 2nd attempt, we retried 1 time.
    If we fail 1st, `retries` is 0. We set `job["retry_count"]` to 0. We increment `retries` to 1.
    Next attempt (1st retry). If success, `job["retry_count"]` becomes 1.
    This means the final value reflects the number of retries performed.
    The intermediate assignment in the `except` block is just for tracking state during failure, but the final success assignment overrides it.
    However, if it fails all 3 retries, the final assignment is in the `else` block.
    `job["retry_count"] = retries` (which is 3).
    This works.

    I'll ensure the code is clean.

    One check: `backoff_delays` indices.
    If `retries` is 0, `backoff_delays[0]` = 1.
    If `retries` is 1, `backoff_delays[1]` = 2.
    If `retries` is 2, `backoff_delays[2]` = 4.
    If `retries` is 3, `backoff_delays[3]` -> Index Error.
    Condition `if retries < max_retries` (3) prevents index 3 access.
    So `retries` max value for access is 2.
    If `retries` is 3, loop ends.
    Correct.

    Final check on requirements:
    1. `process_job` method: Yes.
    2. Retry up to 3 times: Yes (`max_retries = 3`).
    3. Exponential backoff 1s, 2s, 4s: Yes (`backoff_delays`).
    4. Track retry count: Yes (`job["retry_count"]`).
    5. Return True/False: Yes.
    6. Only Python code: Yes.

    I will output the code now.

```python
from typing import Callable, Dict, Any

class JobQueue:
    def __init__(self):
        self.jobs: Dict[str, Any] = {}

    def add_job(self, job_id: str, data: Any) -> None:
        self.jobs[job_id] = {
            "data": data,
            "retry_count": 0,
            "last_backoff": None
        }

    def process_job(self, job_id: str, processor: Callable) -> bool:
        if job_id not in self.jobs:
            return False

        job = self.jobs[job_id]
        max_retries = 3
        backoff_delays = [1, 2, 4]
        retries = 0

        while True:
            try:
                processor(job["data"])
                job["retry_count"] = retries
                return True
            except Exception:
                if retries < max_retries:
                    delay = backoff_delays[retries]
                    job["retry_count"] = retries
                    job["last_backoff"] = delay
                    retries += 1
                else:
                    job["retry_count"] = retries
                    return False
```
    Wait, `job["retry_count"] = retries` inside the `except` block before incrementing `retries` might be confusing if the job is checked mid-process, but since `process_job` is the entry point, the final state is what matters.
    Actually, to be cleaner, I can just update `retry_count` at the end of a successful run or at the end of failure.
    But if I want to track it *per job* (implying persistence), the intermediate update is fine.
    Wait, if I update `job["retry_count"]` to `retries` (which is 0) on the first failure, and then increment `retries` to 1.
    If I succeed next, I update it to 1.
    This is correct.
    I will stick with this logic. It accurately reflects the number of retries attempted before success.

    One tiny optimization: I can remove `job["last_backoff"]` if not strictly needed, but "backoff delays can be stored/tracked" suggests I should store it. I'll keep it.
    Also `job["retry_count"]` inside the `except` block before `retries += 1` sets it to the count of retries *completed* prior to this one.
    Actually, `retries` variable tracks how many retries we have *scheduled* or *attempted* in the loop logic.
    Let's trace `retries` variable vs `job["retry_count"]`.
    Init: `retries` = 0.
    Fail 1st. `retries` = 0. `job["retry_count"]` = 0. `retries` -> 1.
    Fail 2nd. `retries` = 1. `job["retry_count"]` = 1. `retries` -> 2.
    Fail 3rd. `retries` = 2. `job["retry_count"]` = 2. `retries` -> 3.
    Fail 4th. `retries` = 3. `job["retry_count"]` = 3. Return False.
    Success 2nd. `retries` = 1. `job["retry_count"]` = 1. Return True.
    This looks consistent. `job["retry_count"]` represents the number of retries performed.

    Wait, `job["retry_count"]` in the `except` block:
    When `retries` is 0 (First attempt failure), I set `job["retry_count"]` to 0.
    Then I increment `retries` to 1.
    If I succeed on the next loop (which is the 1st retry), `job["retry_count"]` is set to 1.
    So if I succeed on the first retry, the count is 1.
    This implies 1 retry was needed.
    This seems correct.

    Wait, if I succeed on the very first attempt (0 retries).
    `retries` = 0.
    `processor` succeeds.
    `job["retry_count"]` = 0.
    Return True.
    Correct.

    Okay, code is ready.

</reasoning_content>

<content>
```python
from typing import Callable, Dict, Any

class JobQueue:
    def __init__(self):
        self.jobs: Dict[str, Any] = {}

    def add_job(self, job_id: str, data: Any) -> None:
        self.jobs[job_id] = {
            "data": data,
            "retry_count": 0,
            "last_backoff": None
        }

    def process_job(self, job_id: str, processor: Callable) -> bool:
        if job_id not in self.jobs:
            return False

        job = self.jobs[job_id]
        max_retries = 3
        backoff_delays = [1, 2, 4]
        retries = 0

        while True:
            try:
                processor(job["data"])
                job["retry_count"] = retries
                return True
            except Exception:
                if retries < max_retries:
                    delay = backoff_delays[retries]
                    job["retry_count"] = retries
                    job["last_backoff"] = delay
                    retries += 1
                else:
                    job["retry_count"] = retries
                    return False
```
</content>