Logo
Nuevos usuarios de RPC: 35% de descuento el primer mesVer oferta
OnFinality Learn
Solución de problemas de RPC12 min de lectura

Tiempos de espera de RPC en Polygon: Causas, diagnóstico y patrones de reintento

Aprenda por qué las llamadas RPC de Polygon agotan el tiempo de espera, cómo diagnosticar los tiempos de espera a nivel de transporte frente a los de método, y cómo implementar patrones de reintento robustos con retroceso exponencial para Polygon PoS.

TL;DR

Una guía práctica para diagnosticar y resolver los tiempos de espera de RPC en Polygon, cubriendo los tiempos de espera a nivel de transporte y método, la arquitectura Bor/Heimdall de Polygon, y la implementación de patrones de reintento con retroceso exponencial y conmutación por error de endpoints.

Respuesta directa: ¿Qué causa los tiempos de espera de RPC en Polygon y cómo solucionarlos?

Un tiempo de espera de RPC en Polygon ocurre cuando su solicitud a un nodo de Polygon PoS no recibe una respuesta dentro de la ventana de tiempo de espera de su cliente. La causa raíz suele ser una de tres cosas: un problema a nivel de transporte (conectividad de red, DNS o el nodo no es accesible), un problema a nivel de método (el nodo tarda demasiado en calcular una consulta pesada como un eth_getLogs de amplio rango o un eth_call de archivo), o un límite de velocidad que se manifiesta como un tiempo de espera en lugar de un 429. Para solucionarlo, debe distinguir estos casos, establecer tiempos de espera explícitos por llamada, implementar reintentos idempotentes con retroceso exponencial, reducir los rangos de sus consultas y realizar conmutación por error entre endpoints.

Este artículo se centra en Polygon PoS (la cadena compatible con EVM con una arquitectura de dos capas: Heimdall para consenso y Bor para producción de bloques). Cubriremos cómo diagnosticar los tiempos de espera usando las banderas de temporización de curl y las comprobaciones de cabeza de bloque, y luego proporcionaremos código Node.js ejecutable para patrones de reintento y comprobaciones de salud de endpoints. Para problemas relacionados, consulte nuestro artículo sobre latencia y rendimiento de RPC en Polygon para técnicas de medición, y límites de velocidad y errores 429 en Polygon RPC para el manejo específico de límites de velocidad.

  • Tiempo de espera de transporte: tiempo de espera de conexión o lectura antes de que llegue cualquier byte de respuesta.
  • Tiempo de espera a nivel de método: el nodo recibe la solicitud pero tarda más que el tiempo de espera de su cliente en calcular el resultado.
  • Tiempo de espera por límite de velocidad: algunos proveedores devuelven un 429, pero otros pueden cerrar la conexión o retrasar la respuesta, causando un tiempo de espera.

Arquitectura de Polygon PoS y su impacto en los tiempos de espera de RPC

Polygon PoS utiliza una arquitectura de dos capas: Heimdall (basado en Tendermint) maneja el staking, los checkpoints y el consenso, mientras que Bor (una bifurcación de go-ethereum) produce bloques con un tiempo de bloque de ~2 segundos. Las solicitudes RPC son atendidas por los nodos Bor, que mantienen el estado de la cadena y ejecutan consultas. Esta arquitectura afecta los tiempos de espera de dos maneras: la frescura de los datos y la complejidad de las consultas.

Debido a que Bor produce bloques cada 2 segundos, la cabeza de la cadena se mueve rápidamente. Si su nodo está rezagado (por ejemplo, debido a problemas de sincronización), eth_blockNumber puede devolver un valor obsoleto, y las consultas contra bloques recientes pueden fallar o agotar el tiempo de espera si el nodo aún se está poniendo al día. Además, los checkpoints de Heimdall finalizan el estado en Ethereum, pero la finalidad de Bor es probabilística; esto significa que las lecturas del último bloque no están garantizadas como finales, y es posible que deba esperar un cierto número de confirmaciones para evitar reorganizaciones.

Para los tiempos de espera de RPC, la conclusión clave es que las consultas pesadas como eth_getLogs sobre un gran rango de bloques o eth_call que toca muchos slots de almacenamiento pueden tardar segundos en ejecutarse, especialmente en nodos de archivo. La documentación de Polygon señala que eth_getLogs es una llamada intensiva en recursos, y los proveedores a menudo imponen límites en el rango de bloques y el tamaño de la respuesta. Por ejemplo, la referencia de errores de Polygon de QuickNode lista -32005 para 'la consulta excede el límite' y -32001 para 'recurso no encontrado', pero los tiempos de espera no siempre se devuelven como errores; a veces la conexión simplemente se cuelga.

  • Tiempo de bloque de Bor: ~2 segundos, por lo que la cabeza de la cadena se mueve rápido.
  • Los checkpoints de Heimdall finalizan el estado en Ethereum, pero las lecturas de Bor no son inmediatamente finales.
  • Métodos pesados: eth_getLogs, eth_call, eth_getStorageAt, debug_*, trace_* son propensos a tiempos de espera.

Diagnóstico de tiempos de espera de RPC en Polygon: Paso a paso

Antes de cambiar su código, necesita aislar dónde ocurre el tiempo de espera. Use curl con banderas de temporización para medir el tiempo de conexión, el tiempo hasta el primer byte (TTFB) y el tiempo total. Esto le dice si el tiempo de espera es a nivel de transporte o a nivel de método.

Ejecute el siguiente comando contra su endpoint RPC de Polygon. Reemplace YOUR_RPC_URL con su endpoint (por ejemplo, https://polygon-rpc.com o su endpoint de OnFinality). La bandera -w genera variables de temporización: time_connect (handshake TCP), time_starttransfer (TTFB) y time_total (tiempo total de solicitud).

curl -w "\n\nTiempo de conexión: %{time_connect}s\nTiempo hasta el primer byte: %{time_starttransfer}s\nTiempo total: %{time_total}s\n" -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' YOUR_RPC_URL

Interpretación de los resultados

Si time_connect es alto (por ejemplo, > 1 segundo), el problema es de conectividad de red o DNS. Si time_connect es bajo pero time_starttransfer es alto, el nodo es lento para responder, lo que indica un problema a nivel de método o sobrecarga del nodo. Si la solicitud agota el tiempo de espera por completo (curl sale con el código 28), es posible que necesite agregar --max-time para ver temporizaciones parciales.

A continuación, verifique el retraso de la cabeza de bloque. Compare eth_blockNumber de su endpoint contra una referencia independiente, como un explorador de bloques público o un segundo proveedor de RPC. Si el número de bloque de su endpoint está significativamente rezagado (por ejemplo, más de 10 bloques), el nodo puede estar sincronizándose o no estar saludable. Use eth_syncing para ver si el nodo está sincronizado: si devuelve false, el nodo está sincronizado; si devuelve un objeto con currentBlock y highestBlock, todavía se está sincronizando.

curl -s -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}' YOUR_RPC_URL

Implementación de patrones de reintento robustos en Node.js

Una vez que haya identificado que los tiempos de espera son intermitentes o específicos de un método, implemente un patrón de reintento con retroceso exponencial. La clave es solo reintentar solicitudes idempotentes (lecturas) y evitar reintentar escrituras que cambian el estado (como eth_sendRawTransaction) a menos que tenga una manera de deduplicar (por ejemplo, usando un nonce de transacción). Para lecturas, puede reintentar de manera segura con retroceso.

A continuación se muestra un ejemplo ejecutable de Node.js usando ethers.js v6. Define una función callWithRetry que envuelve cualquier método RPC, reintentando en caso de tiempo de espera o errores de red con retroceso exponencial y jitter. También incluye una función de comprobación de salud que compara dos endpoints y devuelve el de menor latencia.

const { ethers } = require('ethers');

// Configuración
const RPC_URLS = [
  'https://polygon-rpc.com',
  'https://polygon.llamarpc.com'
];
const TIMEOUT_MS = 5000;
const MAX_RETRIES = 3;
const BASE_DELAY_MS = 1000;

// Crear proveedores con tiempo de espera explícito
const providers = RPC_URLS.map(url => new ethers.JsonRpcProvider(url, 137, { staticNetwork: true }));
providers.forEach(p => p._getConnection().timeout = TIMEOUT_MS);

// Envoltorio de reintento para llamadas idempotentes
async function callWithRetry(provider, method, params, retries = MAX_RETRIES) {
  try {
    return await provider.send(method, params);
  } catch (error) {
    if (retries === 0) throw error;
    const delay = BASE_DELAY_MS * Math.pow(2, MAX_RETRIES - retries) + Math.random() * 200;
    console.log(`Reintentando en ${delay}ms...`);
    await new Promise(resolve => setTimeout(resolve, delay));
    return callWithRetry(provider, method, params, retries - 1);
  }
}

// Comprobación de salud: comparar números de bloque y latencia
async function healthCheck() {
  const results = [];
  for (const provider of providers) {
    const start = Date.now();
    try {
      const blockNumber = await callWithRetry(provider, 'eth_blockNumber', []);
      const latency = Date.now() - start;
      results.push({ url: provider._getConnection().url, blockNumber: parseInt(blockNumber, 16), latency });
    } catch (error) {
      results.push({ url: provider._getConnection().url, error: error.message });
    }
  }
  return results;
}

// Ejemplo de uso
(async () => {
  const results = await healthCheck();
  console.log('Resultados de la comprobación de salud:', results);
  // Forma esperada de salida:
  // [
  //   { url: 'https://polygon-rpc.com', blockNumber: 12345678, latency: 120 },
  //   { url: 'https://polygon.llamarpc.com', blockNumber: 12345678, latency: 95 }
  // ]
})();

Reducción de consultas pesadas para evitar tiempos de espera

Muchos tiempos de espera son causados por consultas demasiado amplias. Para eth_getLogs, limite el rango de bloques a unos pocos miles de bloques a la vez, y use los parámetros fromBlock y toBlock. Para eth_call, evite llamar a funciones que iteran sobre grandes arrays o acceden a muchos slots de almacenamiento; considere usar un subgraph o un indexador para necesidades de datos complejas. Para eth_getStorageAt, consulte slots específicos en lugar de rangos.

La documentación de Polygon y las referencias de proveedores (por ejemplo, la referencia de errores de QuickNode) recomiendan mantener los rangos de eth_getLogs pequeños. Un patrón común es paginar: obtener logs en fragmentos de 10,000 bloques o menos, y si la respuesta sigue siendo lenta, reduzca el tamaño del fragmento. Además, prefiera eth_subscribe para eventos en tiempo real (newHeads, logs) en lugar de sondeo, ya que reduce el número de solicitudes y evita tiempos de espera por sondeo repetido.

  • Limite el rango de bloques de eth_getLogs a ≤ 10,000 bloques (o menos si los tiempos de espera persisten).
  • Use eth_subscribe para newHeads y logs en lugar de sondeo.
  • Para eth_call, use blockTag para especificar un bloque reciente y evitar búsquedas de archivo.
  • Considere usar un indexador dedicado para consultas complejas.

Conmutación por error de endpoints y comprobaciones de salud

Para aumentar la fiabilidad, implemente conmutación por error entre múltiples endpoints RPC. El fragmento de comprobación de salud anterior compara números de bloque y latencia; puede usarlo para seleccionar el mejor endpoint en tiempo de ejecución. Para producción, considere un balanceador de carga o una biblioteca como FallbackProvider de ethers que enruta automáticamente las solicitudes a endpoints saludables.

Al usar múltiples endpoints, asegúrese de que sean consistentes: si un endpoint está rezagado, puede obtener datos obsoletos. Use un umbral para la diferencia de número de bloque (por ejemplo, dentro de 5 bloques) para considerar un endpoint saludable. Además, tenga en cuenta los límites de velocidad específicos del proveedor; consulte nuestras páginas de precios de RPC y servicio de API para detalles sobre las ofertas de OnFinality, pero tenga en cuenta que los límites de velocidad específicos varían según el proveedor.

// Ejemplo usando FallbackProvider de ethers
const { FallbackProvider } = require('ethers');
const providers = RPC_URLS.map(url => new ethers.JsonRpcProvider(url, 137));
const fallbackProvider = new FallbackProvider(providers, 1); // 1 = quórum
fallbackProvider.on('error', (error) => console.error('Error del proveedor:', error));

// Use fallbackProvider como lo haría con un proveedor normal
const blockNumber = await fallbackProvider.getBlockNumber();
console.log('Número de bloque:', blockNumber);

Fallos comunes y soluciones

Aquí hay escenarios comunes de tiempo de espera y sus soluciones:

  1. Tiempo de espera de transporte en eth_blockNumber: Verifique la conectividad de red, DNS y firewall. Use curl -w para ver si time_connect es alto. Si es así, pruebe con un endpoint diferente o use una VPN.

  1. Tiempo de espera a nivel de método en eth_getLogs: Reduzca el rango de bloques, use paginación o cambie a eth_subscribe para logs en tiempo real. Si necesita logs históricos, considere usar un servicio de datos.

  1. Tiempo de espera en eth_call para un contrato complejo: Optimice la llamada al contrato, use una etiqueta de bloque reciente o use un método de trace/debug si está disponible (pero tenga en cuenta que a menudo están restringidos).

  1. Tiempos de espera intermitentes debido a límites de velocidad: Algunos proveedores devuelven 429, pero otros pueden cerrar conexiones. Implemente retroceso exponencial y considere usar un proveedor con límites más altos o un nodo dedicado.

  • Siempre establezca tiempos de espera explícitos en su cliente RPC (por ejemplo, timeout en ethers).
  • Use reintentos idempotentes con retroceso exponencial y jitter.
  • Monitoree el retraso de la cabeza de bloque y eth_syncing para detectar nodos no saludables.
  • Conmute a un endpoint de respaldo si el principal es lento o está caído.

Compensaciones y limitaciones

Los patrones de reintento agregan latencia y complejidad. El retroceso exponencial puede aumentar el tiempo de respuesta para solicitudes legítimas si el primer intento falla. Además, reintentar transacciones que cambian el estado es peligroso; debe asegurar la idempotencia (por ejemplo, usando el mismo nonce) o arriesgar transacciones duplicadas. Para lecturas, los reintentos son seguros pero pueden amplificar la carga en el proveedor de RPC, así que úselos con prudencia.

Reducir los rangos de consulta reduce el riesgo de tiempo de espera pero puede requerir más solicitudes, aumentando la latencia general y potencialmente alcanzando límites de velocidad. eth_subscribe es eficiente pero requiere una conexión WebSocket, que tiene sus propias consideraciones (consulte nuestra guía de RPC WebSocket de Polygon para más detalles).

Los límites específicos del proveedor varían; siempre consulte la documentación de su proveedor de RPC. Para OnFinality, consulte nuestra guía de RPC de Polygon y la página de red de Polygon para información general, pero tenga en cuenta que los límites de velocidad específicos están documentados por proveedor.

Próximos pasos y lecturas adicionales

Ahora que comprende los tiempos de espera de RPC en Polygon, puede aplicar estos patrones a sus aplicaciones. Para obtener una guía más detallada, explore los siguientes recursos:

  • Implemente el patrón de reintento en su código de producción.
  • Configure monitoreo para la salud y latencia de RPC.
  • Considere usar un nodo dedicado para cargas de trabajo pesadas.

Nunca te preocupes por la infraestructura nuevamente

OnFinality elimina la carga pesada de DevOps para que puedas construir de forma más inteligente y rápida.

Comenzar