---
name: call_batch_with_retry
kind: function
lang: py
domain: core
version: "1.0.0"
purity: impure
signature: "def call_batch_with_retry(items: list[T], process_func: Callable[[T], R], max_retries: int = 3, initial_delay: float = 1.0, max_delay: float = 30.0, backoff_factor: float = 2.0, exceptions: tuple[type[Exception], ...] = (Exception,), continue_on_failure: bool = True) -> tuple[list[R], list[dict]]"
description: "Procesa una lista de items con retry individual por item y exponential backoff. Los fallos individuales no bloquean el resto del batch. Retorna (results, failures) donde failures contiene index, item y error de cada item que agoto sus reintentos."
tags: [retry, batch, backoff, resilience, error-handling, core]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: ["time", "random", "typing.Callable", "typing.TypeVar"]
params:
  - name: items
    desc: "lista de items a procesar"
  - name: process_func
    desc: "funcion que procesa un item individual"
  - name: max_retries
    desc: "numero maximo de reintentos por item"
  - name: initial_delay
    desc: "delay inicial en segundos para exponential backoff"
  - name: max_delay
    desc: "delay maximo en segundos para el backoff"
  - name: backoff_factor
    desc: "factor de multiplicacion para el backoff exponencial"
  - name: exceptions
    desc: "tupla de tipos de excepcion que desencadenan reintentos"
  - name: continue_on_failure
    desc: "si False, aborta el batch en el primer error; si True continua"
output: "tupla (results, failures) donde results es lista de valores y failures es lista de dicts con index/item/error"
tested: true
tests:
  - "todos los items exito"
  - "item falla permanentemente, continue True"
  - "item falla, abort continue False"
  - "item falla luego exito retry funciona"
  - "failures contiene index correcto"
test_file_path: "python/functions/core/call_batch_with_retry_test.py"
file_path: "python/functions/core/call_batch_with_retry.py"
---

## Ejemplo

```python
results, failures = call_batch_with_retry(
    items=["url1", "url2", "url3"],
    process_func=fetch_url,
    max_retries=3,
    initial_delay=1.0,
    max_delay=30.0,
    backoff_factor=2.0,
    exceptions=(ConnectionError, TimeoutError),
    continue_on_failure=True,
)

for r in results:
    print("OK:", r)

for f in failures:
    print(f"FAIL index={f['index']} item={f['item']} error={f['error']}")
```

## Notas

Diferencia con `retry_sync_py_core`: ese reintenta una sola llamada. Este maneja listas completas donde cada item se reintenta independientemente — los fallos individuales quedan registrados en `failures` sin interrumpir el procesamiento del batch (cuando `continue_on_failure=True`).

El backoff usa la formula `min(initial_delay * backoff_factor^attempt, max_delay)` con jitter de hasta el 10% del delay calculado para evitar thundering herd. El primer intento es siempre inmediato — el delay se aplica antes del primer retry (attempt=0).

Cuando `continue_on_failure=False`, el primer item que agota sus reintentos re-lanza la excepcion inmediatamente, abortando el batch.
