Parte de nuestra serie Performance & Scalability
Leer la guía completaUna encuesta de Merge.dev de 2025 encontró que el 62 % de las fallas de integración de API se originan por problemas de entrega de webhooks, pero solo el 23 % de los equipos de ingeniería cuentan con un monitoreo de webhook dedicado. Los webhooks son engañosamente simples (una POST HTTP de un sistema a otro), pero en producción fallan de manera sutil y frustrante.
Esta guía cubre todo el ciclo de vida de los webhooks: desde comprender por qué fallan los webhooks hasta crear flujos de trabajo de depuración sólidos e implementar un monitoreo de nivel de producción que detecte los problemas antes de que lo hagan los usuarios.
Conclusiones clave
- Los webhooks fallan silenciosamente: a diferencia de las llamadas API donde su código recibe una respuesta de error, las fallas de los webhooks ocurren en el lado del remitente y su sistema nunca sabe que se intentó la solicitud a menos que tenga monitoreo.
- Las cinco fallas de webhook más comunes son: punto final inalcanzable (DNS/red), problemas con el certificado SSL, tiempo de espera (el procesamiento tomó demasiado tiempo), análisis de carga útil incorrecto y falla en la verificación de firma.
- La idempotencia es obligatoria: los webhooks se pueden entregar más de una vez debido a los reintentos, por lo que su controlador debe producir el mismo resultado ya sea que procese una carga útil una o diez veces.
- La verificación de firma mediante HMAC-SHA256 es el estándar de la industria para la seguridad de webhooks: nunca procese cargas útiles no verificadas en producción.
- El registro y las alertas estructurados detectan problemas en cuestión de minutos, mientras que las colas de mensajes no entregados garantizan que ningún evento se pierda permanentemente.
1. Fundamentos de la arquitectura del webhook
Antes de depurar, comprenda cómo fluyen los webhooks a través de los sistemas:
┌──────────┐ HTTP POST ┌──────────────┐ Queue ┌──────────────┐
│ Source │ ──────────────────>│ Your Server │ ────────────> │ Processor │
│ (Stripe, │ Headers + JSON │ (Receiver) │ Async job │ (Handler) │
│ Shopify) │ │ │ │ │
└──────────┘ └──────────────┘ └──────────────┘
│ │ │
│ Expects 2xx within │ Verify signature │ Business logic
│ 5-30 seconds │ Parse payload │ Database writes
│ │ Enqueue for processing │ Trigger side effects
│ Retries on failure │ Return 200 immediately │ Log completion
└────────────────────────────────┘ └──────────────────
Principio de diseño crítico: Reconozca el webhook (devuelve 200) lo más rápido posible y luego procéselo de forma asincrónica. La mayoría de los remitentes de webhooks tienen tiempos de espera agresivos (de 5 a 30 segundos) y lo volverán a intentar si su punto final no responde a tiempo.
2. Las cinco fallas más comunes de los webhooks
Fallo 1: punto final inalcanzable
# Symptoms: Sender shows "connection refused" or "DNS resolution failed"
# Common causes:
# - Firewall blocking the sender's IP range
# - DNS misconfiguration after domain migration
# - Load balancer health check failing
# - Server crashed or not started
# Diagnostic steps:
# 1. Test connectivity from outside your network
curl -X POST https://your-domain.com/webhooks/stripe \
-H "Content-Type: application/json" \
-d '{"test": true}' \
-v # Verbose output shows connection details
# 2. Check DNS resolution
nslookup your-domain.com
dig your-domain.com +short
# 3. Check if the port is listening
nc -zv your-domain.com 443
# 4. Check firewall rules (if you have server access)
sudo ufw status
sudo iptables -L -n | grep 443
Fallo 2: Problemas con el certificado SSL
# Symptoms: "SSL handshake failed", "certificate expired", "self-signed cert"
# Webhook senders REQUIRE valid SSL certificates
# Check certificate expiry
echo | openssl s_client -servername your-domain.com -connect your-domain.com:443 2>/dev/null | openssl x509 -noout -dates
# Check full certificate chain
openssl s_client -connect your-domain.com:443 -showcerts < /dev/null 2>/dev/null
# Common fix: renew Let's Encrypt certificate
# sudo certbot renew --force-renewal
# sudo systemctl reload nginx
Fallo 3: Tiempo de espera
# Symptoms: Sender retries because your endpoint took too long
# Solution: Acknowledge immediately, process asynchronously
# BAD: Processing inline (may take 10+ seconds)
@app.route('/webhooks/stripe', methods=['POST'])
def bad_webhook_handler():
event = parse_stripe_event(request)
process_payment(event) # Database queries, external API calls
send_confirmation_email(event) # SMTP call
update_inventory(event) # More database queries
return jsonify({'status': 'ok'}), 200 # Too late — Stripe already timed out
# GOOD: Acknowledge immediately, process in background
@app.route('/webhooks/stripe', methods=['POST'])
def good_webhook_handler():
# Verify signature FIRST (fast)
verify_stripe_signature(request)
# Enqueue for background processing
task_queue.enqueue('process_stripe_event', request.json)
# Return 200 within milliseconds
return jsonify({'status': 'received'}), 200
Fallo 4: errores de análisis de carga útil
# Symptoms: 400/500 errors, "unexpected token", type errors
# Cause: Assumptions about payload structure that break with API updates
# BAD: Assuming structure
def process_order(payload):
customer_email = payload['data']['object']['customer']['email'] # KeyError!
# GOOD: Defensive parsing
def process_order(payload):
try:
data = payload.get('data', {})
obj = data.get('object', {})
customer = obj.get('customer', {})
# Customer might be a string (ID) or an object
if isinstance(customer, str):
customer_email = None # Need to fetch from API
else:
customer_email = customer.get('email')
if not customer_email:
logger.warning(f"No customer email in webhook: {payload.get('id')}")
return
except Exception as e:
logger.exception(f"Failed to parse webhook payload: {e}")
raise
Fallo 5: Fallo en la verificación de firma
import hmac
import hashlib
def verify_stripe_signature(request):
"""Verify Stripe webhook signature."""
payload = request.data # Raw bytes, NOT parsed JSON
sig_header = request.headers.get('Stripe-Signature', '')
webhook_secret = os.environ['STRIPE_WEBHOOK_SECRET']
# Parse the signature header
elements = dict(item.split('=', 1) for item in sig_header.split(','))
timestamp = elements.get('t')
signature = elements.get('v1')
if not timestamp or not signature:
raise ValueError('Missing signature components')
# Compute expected signature
signed_payload = f'{timestamp}.{payload.decode("utf-8")}'
expected = hmac.new(
webhook_secret.encode('utf-8'),
signed_payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, signature):
raise ValueError('Signature verification failed')
# Check timestamp freshness (prevent replay attacks)
import time
tolerance = 300 # 5 minutes
if abs(time.time() - int(timestamp)) > tolerance:
raise ValueError('Webhook timestamp too old')
Errores comunes de verificación de firma:
- Analizar el JSON antes de verificar (altera el cuerpo sin formato)
- Usar el secreto incorrecto (modo de prueba versus modo en vivo)
- No utilizar comparación de tiempo constante (
hmac.compare_digest) - Middleware de marco que modifica el cuerpo de la solicitud antes de que su controlador lo vea.
3. Herramientas de depuración
ngrok: exponer puntos finales locales
# Install and expose local port
ngrok http 3001
# Output:
# Forwarding https://abc123.ngrok-free.app -> http://localhost:3001
# Use this URL as your webhook endpoint in the sender's dashboard
# ngrok provides a web inspector at http://127.0.0.1:4040
# - See every request/response pair
# - Replay failed webhooks
# - Inspect headers and bodies
webhook.site: prueba rápida
# 1. Go to https://webhook.site — get a unique URL
# 2. Configure that URL as your webhook endpoint
# 3. Trigger events and see payloads in real-time
# 4. Copy the payload format for your handler development
curl - Prueba manual
# Simulate a Stripe checkout.session.completed webhook
curl -X POST http://localhost:3001/api/billing/webhook \
-H "Content-Type: application/json" \
-H "Stripe-Signature: t=1616161616,v1=abc123..." \
-d '{
"id": "evt_test_123",
"type": "checkout.session.completed",
"data": {
"object": {
"id": "cs_test_456",
"customer": "cus_test_789",
"amount_total": 4999,
"currency": "usd",
"metadata": {
"product_id": "42",
"user_id": "7"
}
}
}
}'
# Watch for the response status and body
Registro estructurado
import structlog
import json
from datetime import datetime
logger = structlog.get_logger()
def log_webhook_event(request, response_status, processing_time_ms, error=None):
"""Log every webhook with full context for debugging."""
log_data = {
'event': 'webhook_received',
'timestamp': datetime.utcnow().isoformat(),
'source': detect_webhook_source(request),
'event_type': request.json.get('type', 'unknown'),
'event_id': request.json.get('id', 'unknown'),
'method': request.method,
'path': request.path,
'content_length': request.content_length,
'response_status': response_status,
'processing_time_ms': processing_time_ms,
'ip_address': request.remote_addr,
'user_agent': request.headers.get('User-Agent', ''),
}
if error:
log_data['error'] = str(error)
log_data['error_type'] = type(error).__name__
logger.error('webhook_failed', **log_data)
else:
logger.info('webhook_processed', **log_data)
4. Estrategias de reintento
La mayoría de los remitentes de webhooks implementan reintentos automáticos con retroceso exponencial. Stripe lo reintenta hasta 3 veces en 24 horas. Shopify lo vuelve a intentar hasta 19 veces en 48 horas. Su sistema debe estar diseñado para manejar entregas duplicadas a través de claves de idempotencia y debe implementar su propia cola de reintento para procesar fallas, de modo que los errores transitorios, como los tiempos de espera de la base de datos, no pierdan eventos permanentemente.
Políticas de reintento del remitente
| Plataforma | Reintentos máximos | Ventana de tiempo de espera | Patrón de retroceso |
|---|---|---|---|
| Raya | 3 | 24 horas | Exponencial |
| Shopify | 19 | 48 horas | Exponencial |
| GitHub | 3 | 1 hora | Fijo (10 min) |
| PayPal | 15 | 3 días | Exponencial |
| Twilio | 1 | Inmediato | Ninguno |
Construyendo su propia cola de reintentos
// Node.js retry queue with exponential backoff
const Bull = require('bull');
const webhookQueue = new Bull('webhooks', {
redis: { host: 'localhost', port: 6379 },
defaultJobOptions: {
attempts: 5,
backoff: {
type: 'exponential',
delay: 2000, // 2s, 4s, 8s, 16s, 32s
},
removeOnComplete: 100,
removeOnFail: false, // Keep failed jobs for analysis
},
});
// Producer: enqueue webhook for processing
async function enqueueWebhook(eventType, payload, source) {
await webhookQueue.add(eventType, {
payload,
source,
receivedAt: new Date().toISOString(),
idempotencyKey: payload.id || `${source}-${Date.now()}`,
});
}
// Consumer: process webhooks
webhookQueue.process('checkout.session.completed', async (job) => {
const { payload, idempotencyKey } = job.data;
// Check idempotency
const processed = await redis.get(`webhook:${idempotencyKey}`);
if (processed) {
console.log(`Skipping duplicate webhook: ${idempotencyKey}`);
return { status: 'duplicate', key: idempotencyKey };
}
try {
// Process the event
await handleCheckoutCompleted(payload);
// Mark as processed (TTL 48h)
await redis.setex(`webhook:${idempotencyKey}`, 172800, 'processed');
return { status: 'success' };
} catch (error) {
// Will be retried automatically by Bull
throw error;
}
});
// Dead letter handler
webhookQueue.on('failed', (job, error) => {
if (job.attemptsMade >= job.opts.attempts) {
console.error(`Webhook permanently failed after ${job.attemptsMade} attempts:`, {
eventType: job.name,
idempotencyKey: job.data.idempotencyKey,
error: error.message,
});
// Send alert to Slack/PagerDuty
alertService.sendCritical('Webhook permanently failed', {
job: job.id,
event: job.name,
error: error.message,
});
}
});
5. Implementación de la idempotencia
import hashlib
import redis
redis_client = redis.Redis(host='localhost', port=6379, db=0)
def process_webhook_idempotently(event_id, event_type, payload, handler_fn):
"""Ensure a webhook is processed exactly once."""
# Create idempotency key
idem_key = f"webhook:processed:{event_id}"
# Check if already processed (atomic operation)
if redis_client.exists(idem_key):
logger.info(f"Skipping duplicate webhook: {event_id}")
return {'status': 'duplicate'}
# Set a processing lock (prevents concurrent processing)
lock_key = f"webhook:lock:{event_id}"
lock_acquired = redis_client.set(lock_key, '1', nx=True, ex=60)
if not lock_acquired:
logger.warning(f"Webhook already being processed: {event_id}")
return {'status': 'in_progress'}
try:
# Process the event
result = handler_fn(event_type, payload)
# Mark as processed (keep for 48 hours)
redis_client.setex(idem_key, 172800, json.dumps({
'processed_at': datetime.utcnow().isoformat(),
'result': str(result),
}))
return {'status': 'processed', 'result': result}
except Exception as e:
# Release lock so it can be retried
redis_client.delete(lock_key)
raise
finally:
redis_client.delete(lock_key)
6. Panel de seguimiento
Métricas clave para realizar un seguimiento
| Métrica | Objetivo | Umbral de alerta |
|---|---|---|
| Tasa de éxito de entrega | > 99,5% | < 98% |
| Tiempo medio de procesamiento | < 500 ms | > 2000ms |
| Profundidad de la cola | < 100 | > 500 |
| Tasa duplicada | < 5% | > 15% |
| Fallos en la verificación de firma | 0 | > 3/hora |
| Tamaño de la cola de mensajes fallidos | 0 | > 10 |
Ejemplo de métricas de Prometheus
from prometheus_client import Counter, Histogram, Gauge
# Counters
webhook_received_total = Counter(
'webhook_received_total',
'Total webhooks received',
['source', 'event_type']
)
webhook_processed_total = Counter(
'webhook_processed_total',
'Total webhooks successfully processed',
['source', 'event_type']
)
webhook_failed_total = Counter(
'webhook_failed_total',
'Total webhook processing failures',
['source', 'event_type', 'error_type']
)
webhook_duplicate_total = Counter(
'webhook_duplicate_total',
'Duplicate webhook deliveries skipped',
['source']
)
# Histograms
webhook_processing_duration = Histogram(
'webhook_processing_duration_seconds',
'Time to process a webhook',
['source', 'event_type'],
buckets=[0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0]
)
# Gauges
webhook_queue_depth = Gauge(
'webhook_queue_depth',
'Current number of webhooks waiting to be processed',
['source']
)
Punto final de verificación de estado
// NestJS health check example
@Controller('health')
export class HealthController {
@Get('webhooks')
async webhookHealth() {
const stats = await this.webhookService.getStats();
const healthy = stats.failureRate < 0.02
&& stats.queueDepth < 500
&& stats.avgProcessingTimeMs < 2000
&& stats.deadLetterCount < 10;
return {
status: healthy ? 'healthy' : 'degraded',
metrics: {
totalReceived24h: stats.totalReceived,
successRate: `${((1 - stats.failureRate) * 100).toFixed(2)}%`,
avgProcessingTimeMs: stats.avgProcessingTimeMs,
queueDepth: stats.queueDepth,
deadLetterCount: stats.deadLetterCount,
duplicateRate: `${(stats.duplicateRate * 100).toFixed(2)}%`,
lastReceivedAt: stats.lastReceivedAt,
},
};
}
}
7. Mejores prácticas de seguridad
Lista blanca de IP
# Nginx configuration for webhook endpoints
location /api/webhooks/stripe {
# Only allow Stripe's IP ranges
# https://stripe.com/docs/ips
allow 3.18.12.63;
allow 3.130.192.0/24;
allow 13.235.14.0/24;
allow 18.211.135.0/24;
allow 35.154.171.0/24;
deny all;
proxy_pass http://localhost:3001;
}
Solicitar lista de verificación de validación
- Verificar la firma criptográfica (HMAC-SHA256)
- Verifique que la marca de tiempo esté dentro de la tolerancia (5 minutos)
- Valide el encabezado del tipo de contenido.
- Verifique que el tamaño de la carga útil esté dentro de los límites (rechazar > 1 MB)
- Valide el tipo de evento esperado.
- Verifique la dirección IP si el remitente publica rangos
- Limitar la velocidad del punto final (evitar abusos)
def validate_webhook_request(request):
"""Comprehensive webhook request validation."""
errors = []
# 1. Content-Type
if request.content_type != 'application/json':
errors.append(f'Invalid Content-Type: {request.content_type}')
# 2. Payload size (max 1MB)
if request.content_length and request.content_length > 1_048_576:
errors.append(f'Payload too large: {request.content_length} bytes')
# 3. Required headers
if not request.headers.get('X-Webhook-Signature'):
errors.append('Missing signature header')
# 4. Valid JSON
try:
payload = request.json
except Exception:
errors.append('Invalid JSON payload')
return errors
# 5. Required fields
if 'type' not in payload:
errors.append('Missing event type')
if 'id' not in payload:
errors.append('Missing event ID')
return errors
8. Lista de verificación de depuración
Cuando un webhook deja de funcionar, siga este enfoque sistemático:
- Consulta el panel del remitente: la mayoría de las plataformas (Stripe, Shopify, GitHub) muestran intentos de entrega, códigos de respuesta y marcas de tiempo.
- Verifique los registros de su servidor: busque los registros de acceso al punto final del webhook en Nginx/Apache
- Verificar el certificado SSL: los certificados caducados son el asesino silencioso número uno
- Prueba con curl: PUBLICAR manualmente en su punto final desde una red diferente
- Verifique la resolución de DNS: asegúrese de que su dominio se resuelva correctamente desde redes externas
- Verificar el secreto del webhook: los secretos rotan durante cambios clave o migraciones de entorno
- Compruebe si hay cambios en el formato de la carga útil: las actualizaciones de la versión API pueden cambiar las cargas útiles del webhook
- Revisar implementaciones recientes: es posible que los cambios en el código hayan roto el controlador
- Verifique los límites de recursos: memoria, CPU, conexiones de base de datos
- Pruebe todo el proceso de procesamiento: verifique las escrituras en la base de datos, el procesamiento de colas y los efectos secundarios.
Preguntas frecuentes
¿Cómo pruebo webhooks en desarrollo local?
Utilice ngrok o una herramienta de túnel similar para exponer su servidor local a Internet. Ejecute 'ngrok http 3001' para obtener una URL pública que reenvíe a localhost:3001. Configure esta URL como punto final del webhook en el panel del remitente. El inspector web de ngrok en localhost:4040 le permite inspeccionar cada solicitud y reproducir entregas fallidas. Para CI/CD, utilice servidores simulados o patrones de reproducción de grabaciones.
¿Qué debería devolver mi punto final de webhook?
Devuelve un código de estado 200 lo más rápido posible, entre 2 y 5 segundos. El remitente normalmente ignora el cuerpo de la respuesta, pero un JSON simple como {"status":"received"} es una buena práctica. Devuelve 200 incluso si planeas procesar el evento de forma asincrónica. Solo devuelve 4xx si la firma no es válida o la carga útil tiene un formato incorrecto. Nunca devuelva 5xx por errores de lógica empresarial; en su lugar, regístrelos y procese en una cola de reintentos.
¿Cómo manejo los eventos de webhook que llegan desordenados?
Los eventos pueden llegar desordenados debido a reintentos y condiciones de la red. Incluya una marca de tiempo o una verificación de número de secuencia en su controlador. Para Stripe, use la marca de tiempo creada del evento. Para Shopify, revisa el campo actualizado_at. Si llega un evento que hace referencia a un estado que su sistema aún no ha visto, póngalo en cola para su procesamiento posterior o obtenga el estado actual de la API del remitente para conciliarlo. Las claves de idempotencia evitan el procesamiento duplicado independientemente del orden.
¿Cuál es la mejor manera de monitorear la confiabilidad del webhook?
Realice un seguimiento de cuatro métricas clave: tasa de éxito de entrega (objetivo superior al 99,5%), tiempo de procesamiento promedio (objetivo inferior a 500 milisegundos), profundidad de la cola (objetivo inferior a 100) y tamaño de la cola de mensajes fallidos (objetivo cero). Configure alertas para cuando alguna métrica cruce su umbral. Utilice Prometheus con Grafana para paneles o un servicio administrado como Datadog o New Relic. Supervise también el panel de webhook del remitente para detectar errores de entrega que quizás no vea en sus propios registros.
¿Cómo evito los ataques de repetición de webhooks?
Implemente tres defensas: primero, verifique la firma criptográfica en cada solicitud utilizando HMAC-SHA256 con un secreto compartido. En segundo lugar, verifique la marca de tiempo en la carga útil firmada y rechace los eventos de más de 5 minutos (Stripe incluye esto en su esquema de firma). En tercer lugar, utilice claves de idempotencia para garantizar que cada evento se procese exactamente una vez, incluso si un atacante reproduce una solicitud firmada válida dentro de la ventana de marca de tiempo.
Próximos pasos
La confiabilidad del webhook es la base de las integraciones basadas en eventos. Los patrones de esta guía (verificación de firmas, procesamiento idempotente, colas asíncronas, monitoreo estructurado) se aplican independientemente de las plataformas que esté integrando.
Recursos relacionados:
- Tutorial de API REST de Odoo — Integración de API con Odoo
- Conectores de ECOSIRE Marketplace — Integraciones de Odoo prediseñadas
- Mejor ERP para comercio electrónico 2026 — Comparación de ERP listo para la integración
ECOSIRE crea integraciones de webhooks de nivel de producción que conectan Odoo, Shopify, Stripe y docenas de otras plataformas. Nuestros servicios de integración incluyen paneles de control, gestión de colas de mensajes no entregados y garantías de entrega del 99,9 %. Hable con nuestros ingenieros de integración.
Escrito por
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
ECOSIRE
Haga crecer su negocio con ECOSIRE
Soluciones empresariales en ERP, comercio electrónico, inteligencia artificial, análisis y automatización.
Artículos relacionados
Integración de eMAG Odoo: conecte el mercado más grande de Rumania a su ERP (pedidos, stock, e-Factura)
Conecte eMAG Marketplace a Odoo ERP: sincronización de ofertas y pedidos, envío AWB, devoluciones, actualizaciones de stock y precios, además de cumplimiento de e-Factura rumano para vendedores.
Integración profunda de Shopify-Odoo 2026: inventario, pedidos, sincronización contable
Diseñe un conector Shopify-Odoo de producción: inventario bidireccional, sincronización de pedidos, integración contable, almacén múltiple, devoluciones, procesamiento idempotente.
Shopify Webhooks 2026: HMAC, reintentos, idempotencia en producción
Cree receptores de webhooks de Shopify confiables: verificación HMAC, estrategias de reintento, idempotencia, colas de mensajes fallidos y patrones de procesamiento de al menos una vez.
Más de Performance & Scalability
Optimización de la velocidad de Shopify: una lista de verificación técnica que realmente mueve los elementos básicos de la web (2026)
Una lista de verificación de velocidad de Shopify probada en campo para 2026: qué realmente mejora LCP, INP y CLS en tiendas reales, qué es una pérdida de tiempo y cómo auditar aplicaciones y temas.
Lista de verificación de auditoría técnica de SEO 2026: 47 comprobaciones que realizamos en el sitio de cada cliente
La lista de verificación de auditoría técnica de SEO de 47 puntos que ejecutamos en el sitio de cada cliente en 2026: rastreabilidad, indexación, canónicos, hreflang, Core Web Vitals y registros.
Odoo 19 RRHH: Matriz de Habilidades, Planes de Carrera, Ciclos de Desempeño
Actualización de recursos humanos de Odoo 19: matriz de habilidades nativas, planificación de trayectoria profesional, ciclos de revisión del desempeño, cuadrícula de 9 casillas, planificación de sucesión, integración HRIS.
Puntos de referencia de rendimiento de Odoo 19: números de ajuste de PostgreSQL 17
Puntos de referencia de rendimiento de Odoo 19 en el mundo real: velocidad del cliente web, rendimiento de ORM, configuración de ajuste de PG17, agrupación de conexiones, recuento de trabajadores, umbrales de escala.
Optimización de costos de OpenClaw y eficiencia de tokens a escala
Optimización de costos de tokens OpenClaw: almacenamiento en caché de avisos, enrutamiento de modelos, almacenamiento en caché de respuestas, API por lotes y barreras de costos por inquilino para agentes de producción.
Actualización incremental de Power BI para tablas de más de 10 millones de filas
Guía de actualización incremental de Power BI para tablas de más de 10 millones de filas: diseño de particiones, RangeStart/RangeEnd, políticas de actualización, plegado de consultas e híbridos de DirectQuery.