Saltar al contenido principal
Estamos ampliando activamente el soporte para webhooks.Recién llegado: reintentos automáticos con retroceso exponencial — las entregas fallidas ahora se reintentan hasta 5 veces en 30 minutos.Próximamente:
  • URLs de webhook predeterminadas para todo el equipo
  • Firmas criptográficas para la verificación de cargas útiles
¿Quieres acceso anticipado? Contáctanos en info@olostep.com o únete a nuestra comunidad de Slack.

Descripción general

Los webhooks entregan notificaciones HTTP POST en tiempo real a tu servidor cuando las operaciones de larga duración se completan. En lugar de sondear para obtener el estado, tu aplicación recibe actualizaciones instantáneas.

Casos de uso

Procesamiento Asíncrono

Recibe notificaciones cuando los lotes o rastreos se completan en lugar de sondear

Disparadores de Pipeline

Activa automáticamente el procesamiento posterior cuando los datos estén listos

Alertas

Envía alertas a Slack, email u otros sistemas al completarse

Sincronización de Datos

Mantén tu base de datos sincronizada con los resultados de Olostep

Eventos Soportados

Se activa cuando un lote termina de procesarse (todos los elementos completados o fallidos).
{
  "id": "event_a1b2c3d4e5f6g7h8",
  "object": "event.batch.completed",
  "timestamp": 1737570000000,
  "delivery_attempt": "1/5",
  "data": {
    "id": "batch_xyz123",
    "object": "batch",
    "status": "completed",
    "items_total": 100,
    "items_completed": 98,
    "items_failed": 2,
    "created_at": "2024-01-15T10:00:00Z",
    "completed_at": "2024-01-15T10:05:32Z"
  }
}
Se activa cuando un rastreo termina y todas las páginas descubiertas han sido procesadas.
{
  "id": "event_x9y8z7w6v5u4t3s2",
  "object": "event.crawl.completed",
  "timestamp": 1737570000000,
  "delivery_attempt": "1/5",
  "data": {
    "id": "crawl_abc789",
    "object": "crawl",
    "status": "completed",
    "start_url": "https://example.com",
    "urls_count": 87,
    "max_pages": 100,
    "max_depth": 3,
    "actual_max_depth": 3,
    "start_epoch": 1737569500000,
    "start_date": "2024-01-15"
  }
}

Configuración de Webhooks

Pasa webhook al crear un recurso. Esta URL recibe la notificación de finalización.
Nombre del parámetro: El parámetro canónico es webhook. Para compatibilidad con versiones anteriores, webhook_url también se acepta como un alias.
import requests

# Ejemplo de lote
response = requests.post(
    "https://api.olostep.com/v1/batches",
    headers={"Authorization": "Bearer <YOUR_API_KEY>"},
    json={
        "items": [
            {"url": "https://example.com/page1", "custom_id": "1"},
            {"url": "https://example.com/page2", "custom_id": "2"}
        ],
        "webhook": "https://your-server.com/webhooks/olostep"
    }
)

# Ejemplo de rastreo
response = requests.post(
    "https://api.olostep.com/v1/crawls",
    headers={"Authorization": "Bearer <YOUR_API_KEY>"},
    json={
        "start_url": "https://example.com",
        "max_pages": 50,
        "webhook": "https://your-server.com/webhooks/olostep"
    }
)

Carga Útil del Webhook

Todas las cargas útiles de webhook siguen una estructura de sobre unificada:
{
  "id": "event_a1b2c3d4e5f6g7h8",
  "object": "event.batch.completed",
  "timestamp": 1737570000000,
  "delivery_attempt": "1/5",
  "data": {
    "id": "batch_xyz123",
    "object": "batch",
    "status": "completed",
    "items_total": 100,
    "items_completed": 98,
    "items_failed": 2
  }
}

Campos del Sobre

CampoDescripción
idID del evento — igual en todos los intentos de reintento
objectTipo de evento (e.g., event.batch.completed)
timestampCuándo se envió este intento de entrega (epoch ms)
delivery_attemptIntento actual / intentos máximos (e.g., 1/5, 3/5)
dataLos datos reales del recurso (mismo formato que la respuesta de la API)
Usa el campo id para eliminar duplicados en las entregas de webhooks en tu receptor. El mismo ID de evento aparece en todos los intentos de reintento.

Comportamiento de Reintento

Las entregas fallidas de webhooks se reintentan automáticamente con retroceso exponencial durante una ventana de 30 minutos:
IntentoRetraso antes del intentoTiempo acumulado
1Inmediato0 min
2~2 min~2 min
3~4 min~6 min
4~7 min~13 min
5~15 min~28 min
Ventana total de reintento: 30 minutos
Tiempo de espera por solicitud: 30 segundos

Qué Cuenta como Éxito

Tu endpoint debe devolver un código de estado 2xx dentro de 30 segundos. Cualquier otra respuesta desencadena un reintento.
RespuestaResultado
200 OK✅ Entregado
201 Created✅ Entregado
301 Redirect❌ Reintento (no seguimos redirecciones)
400 Bad Request❌ Reintento
500 Server Error❌ Reintento
Tiempo de espera (>30s)❌ Reintento
Conexión rechazada❌ Reintento

Mejores Prácticas

Devuelve 200 OK inmediatamente y procesa el webhook de forma asíncrona. Si tu procesamiento tarda más de 30 segundos, reintentaremos — causando entregas duplicadas.
from queue import Queue
import threading

webhook_queue = Queue()

@app.route('/webhooks/olostep', methods=['POST'])
def handle_webhook():
    # Cola para procesamiento asíncrono
    webhook_queue.put(request.json)
    
    # Devuelve inmediatamente
    return 'OK', 200

def process_webhooks():
    while True:
        event = webhook_queue.get()
        # El procesamiento lento ocurre aquí
        process_event(event)

threading.Thread(target=process_webhooks, daemon=True).start()
Usa el campo id para eliminar duplicados. Almacena los IDs de eventos procesados y omite duplicados.
processed_events = set()  # Usa Redis/DB en producción

def handle_event(event):
    if event['id'] in processed_events:
        return  # Ya procesado
    
    # Procesa el evento
    process_batch_completed(event['data'])
    
    # Marca como procesado
    processed_events.add(event['id'])
Registra todos los recibos de webhooks para depuración. Incluye el ID del evento, la marca de tiempo y el resultado del procesamiento.
import logging

@app.route('/webhooks/olostep', methods=['POST'])
def handle_webhook():
    event = request.json
    logging.info(f"Webhook recibido: id={event['id']} tipo={event['object']} intento={event['delivery_attempt']}")
    
    try:
        process_event(event)
        logging.info(f"Webhook procesado: id={event['id']}")
    except Exception as e:
        logging.error(f"Webhook fallido: id={event['id']} error={e}")
        raise
    
    return 'OK', 200
Siempre usa HTTPS para los endpoints de webhooks. Los endpoints HTTP son vulnerables a escuchas y ataques de intermediario.

Solución de Problemas

  1. Verifica que el parámetro webhook se incluyó en tu solicitud
  2. Verifica que tu endpoint sea accesible públicamente (no localhost)
  3. Revisa los registros de tu servidor para solicitudes entrantes
  4. Asegúrate de devolver un código de estado 2xx
Esto es esperado durante los reintentos. Implementa un manejo idempotente usando el campo id:
def handle_event(event):
    if already_processed(event['id']):
        return  # Omitir duplicado
    
    process_event(event)
    mark_processed(event['id'])
Tu endpoint debe responder dentro de 30 segundos. Procesa los webhooks de forma asíncrona:
@app.route('/webhooks', methods=['POST'])
def webhook():
    queue.enqueue(process_webhook, request.json)
    return 'OK', 200  # Responde inmediatamente

Próximamente

URL Predeterminada del Equipo

Configura una URL de webhook predeterminada en la configuración de tu cuenta. Todas las solicitudes usarán esta URL a menos que se sobrescriba.

Verificación de Firmas

Firmas criptográficas (HMAC-SHA256) para verificar que las cargas útiles de webhook provienen de Olostep.
¿Quieres acceso anticipado a estas funciones? Contáctanos en info@olostep.com o únete a nuestra comunidad de Slack.