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 Sui RPC: JSON-RPC vs gRPC, QueryWeight y patrones de reintento confiables

Aprenda por qué las solicitudes de Sui RPC se agotan, cómo afectan QueryWeight y las opciones de transporte a los tiempos de espera, y cómo diagnosticarlos y solucionarlos con patrones de reintento y conmutación por error de endpoints.

TL;DR

Los tiempos de espera de Sui RPC a menudo son causados por consultas pesadas que exceden los límites de QueryWeight, tiempos de espera a nivel de transporte o sobrecarga del nodo. Este artículo explica las diferencias entre los transportes JSON-RPC, gRPC y GraphQL, cómo QueryWeight afecta la ejecución de solicitudes, y proporciona un ejemplo ejecutable de Node.js con lógica de tiempo de espera y reintento. También incluye una lista de verificación de solución de problemas y orientación sobre conmutación por error de endpoints.

Respuesta directa: Por qué las solicitudes de Sui RPC se agotan

Los tiempos de espera de Sui RPC ocurren cuando una solicitud tarda más de lo que permite el cliente o el servidor, a menudo porque la consulta es demasiado pesada (excede los límites de QueryWeight de Sui), el transporte (JSON-RPC vs gRPC) tiene diferentes características de tiempo de espera, o el nodo está sobrecargado. La causa más común es solicitar demasiados datos en una sola llamada, por ejemplo, obtener un bloque de transacciones con opciones completas o paginar a través de miles de campos dinámicos sin límites adecuados. Este artículo explica los mecanismos subyacentes y proporciona soluciones concretas, incluido el establecimiento de tiempos de espera y reintentos explícitos en el SDK @mysten/sui.js, la reducción de las opciones de consulta y la conmutación por error entre endpoints.

A diferencia de un límite de velocidad (que devuelve un 429 o similar), un tiempo de espera puede manifestarse como un error a nivel de transporte (por ejemplo, 'ETIMEDOUT'), un 500/503 con 'request timed out', o una parada que eventualmente produce un error. Comprender la diferencia es clave para elegir la solución correcta. Para una inmersión más profunda en los límites de velocidad, consulte nuestro artículo Límites de velocidad de Sui RPC y (posiblemente) unidades de cómputo.

  • Tiempos de espera de transporte: límites del lado del cliente o del servidor en el tiempo de conexión o respuesta.
  • QueryWeight: la facturación de cómputo por solicitud de Sui que puede hacer que las consultas pesadas sean rechazadas o tarden demasiado.
  • Sobrecarga del nodo: los nodos compartidos o con recursos insuficientes pueden no responder dentro de su ventana de tiempo de espera.

Transportes de Sui RPC: JSON-RPC, gRPC y GraphQL

Sui ofrece múltiples transportes RPC, cada uno con diferentes características de tiempo de espera y encuadre. El transporte principal es JSON-RPC sobre HTTP, que es síncrono y de solicitud-respuesta. Los tiempos de espera se establecen típicamente en el cliente HTTP (por ejemplo, 30 segundos) y en el lado del servidor (por ejemplo, 60 segundos). Si una consulta tarda más que el tiempo de espera del servidor, puede obtener un 500 o 503 con un mensaje de 'request timed out'.

gRPC es un protocolo binario que admite transmisión y tiene plazos integrados. La interfaz gRPC de Sui (utilizada por el Fullnode de Sui) permite una transmisión más eficiente de grandes conjuntos de datos, como datos de checkpoint. Los tiempos de espera de gRPC se establecen mediante plazos de contexto, y el protocolo maneja la cancelación de manera más elegante. Para transmisión de baja latencia, a menudo se prefiere gRPC, pero requiere un cliente gRPC y no es tan ampliamente compatible como JSON-RPC.

GraphQL (RPC 2.0 de Sui) es una opción emergente que permite a los clientes solicitar exactamente los campos que necesitan, reduciendo el tamaño del payload y los posibles tiempos de espera. A partir de 2026, todavía está en desarrollo (consulte el problema de RPC 2.0 en GitHub), pero promete mitigar los problemas de tiempo de espera evitando la sobrecarga de datos.

  • JSON-RPC: simple, ampliamente compatible, pero síncrono y propenso a tiempos de espera en consultas pesadas.
  • gRPC: binario, transmisión, con plazos; mejor para transferencias de datos grandes.
  • GraphQL: la selección de campos reduce el payload, pero aún no es estable.

QueryWeight: Cómo Sui factura el cómputo por solicitud

Los nodos de Sui utilizan un mecanismo de QueryWeight para limitar el costo computacional de cada solicitud RPC. Cada tipo de consulta tiene un peso, y el nodo tiene un peso máximo por solicitud y por segundo. Si una solicitud excede el peso por solicitud, puede ser rechazada con un error como 'Query is too heavy' o puede tardar tanto que se agote el tiempo. Los límites exactos están documentados en la documentación de Sui y varían según la configuración del nodo.

Las consultas pesadas que comúnmente causan tiempos de espera incluyen:

getTransactionBlock con showInput: true, showEffects: true y showEvents: true—esto puede devolver un payload masivo.

getCoins o multiGetCoins con un limit grande (por ejemplo, 1000) y sin paginación.

getDynamicFields con un limit grande y recursión profunda.

getCheckpoint con showContents: true para un checkpoint con muchas transacciones.

Para evitar tiempos de espera, debe reducir las opciones a solo lo que necesita. Por ejemplo, use showEffects: false si solo necesita el digest, o use multiGetCoins con un límite más pequeño y pagine usando nextCursor.

  • QueryWeight es por solicitud y por segundo; excederlo puede causar tiempos de espera o errores.
  • Solicite siempre solo los campos que necesita.
  • Use paginación para dividir consultas grandes en fragmentos más pequeños.

Diagnóstico de tiempos de espera de Sui RPC

Para diagnosticar un tiempo de espera, comience midiendo el tiempo de respuesta de una consulta simple versus una pesada. Use curl con indicadores de tiempo para ver dónde ocurre el retraso. Por ejemplo:

curl -w "time_total: %{time_total}s\n" https://fullnode.mainnet.sui.io/ -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","method":"sui_getChainIdentifier","params":[],"id":1}'

Si la consulta simple responde rápidamente pero una consulta pesada se agota, el problema es probablemente QueryWeight o el tamaño del payload. Si incluso las consultas simples se agotan, el nodo puede estar sobrecargado o su conexión de red es lenta.

También verifique el estado de sincronización del nodo. Si el nodo está rezagado con respecto a la red, puede no tener los datos que está solicitando, lo que causa que se cuelgue. Compare el último checkpoint o época con un explorador independiente como Sui Explorer para ver si su nodo está atrasado.

  • Use curl -w para medir el tiempo total y el tiempo hasta el primer byte.
  • Compare consultas simples vs pesadas para aislar la causa.
  • Verifique el estado de sincronización del nodo contra un explorador independiente.

Solucionar tiempos de espera: configuración del SDK y patrones de reintento

El SDK de TypeScript @mysten/sui.js le permite establecer un tiempo de espera en el cliente JSON-RPC. Por ejemplo, puede crear un JsonRpcProvider personalizado con una función fetch que incluya un AbortController con un tiempo de espera. Aquí hay un ejemplo ejecutable de Node.js que establece un tiempo de espera de 10 segundos e implementa reintentos con retroceso exponencial:

import { SuiClient, getFullnodeUrl } from '@mysten/sui.js/client';

const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));

async function rpcWithRetry(client, method, params, { timeoutMs = 10000, retries = 3 } = {}) {
  for (let attempt = 0; attempt < retries; attempt++) {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), timeoutMs);
    try {
      const result = await client.call(method, params, { signal: controller.signal });
      clearTimeout(timeout);
      return result;
    } catch (error) {
      clearTimeout(timeout);
      if (attempt === retries - 1) throw error;
      const delay = Math.pow(2, attempt) * 1000;
      console.log(`Attempt ${attempt + 1} failed: ${error.message}. Retrying in ${delay}ms`);
      await sleep(delay);
    }
  }
}

const client = new SuiClient({ url: getFullnodeUrl('mainnet') });

// Example: get a transaction block with minimal options
const txDigest = 'your_tx_digest_here';
const result = await rpcWithRetry(client, 'sui_getTransactionBlock', [txDigest, { showEffects: false }]);
console.log(JSON.stringify(result, null, 2));
// Expected output: a JSON object with the transaction block data, or an error after retries.

Además de los tiempos de espera, debe reducir sus opciones de consulta. Para getTransactionBlock, use showEffects: false a menos que necesite los efectos. Para getCoins, use un limit de 50 o 100 y pagine con nextCursor. Para getDynamicFields, use un limit y evite la recursión profunda.

Si está usando gRPC, establezca un plazo en el contexto. Por ejemplo, en Node.js con la biblioteca @grpc/grpc-js, puede establecer un plazo de 10 segundos. gRPC también admite cancelación, lo que puede ser útil para transmisiones de larga duración.

  • Establezca tiempos de espera explícitos en su cliente HTTP para evitar cuelgues indefinidos.
  • Implemente reintentos con retroceso exponencial para fallos transitorios.
  • Reduzca las opciones de consulta para disminuir el tamaño del payload y el peso de cómputo.
  • Use multiGetCoins en lugar de bucles de getCoins para múltiples tipos de monedas.

Ejemplo ejecutable: tiempo de espera, reintento con retroceso y verificación de salud con el SDK de TypeScript de Sui

El siguiente script de Node.js demuestra un ejemplo completo y autónomo usando @mysten/sui/client. Crea un SuiClient, envuelve una llamada getObject en un tiempo de espera con reintento de retroceso exponencial, y realiza una verificación de salud simple del endpoint obteniendo el identificador de la cadena. El ejemplo está diseñado para ejecutarse tal cual después de instalar el SDK.

Cuando ejecute este script, debería ver una salida similar a la siguiente. Primero, la verificación de salud imprime el identificador de la cadena (una cadena hexadecimal). Luego, la llamada getObject devuelve un objeto JSON con los detalles del objeto solicitado, incluido su tipo y digest. Si el endpoint está caído o la solicitud se agota, la lógica de reintento registra cada intento fallido y eventualmente lanza un error, que se captura e imprime.

import { SuiClient, getFullnodeUrl } from '@mysten/sui/client';

const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));

async function rpcWithRetry(client, method, params, { timeoutMs = 10000, retries = 3 } = {}) {
  for (let attempt = 0; attempt < retries; attempt++) {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), timeoutMs);
    try {
      const result = await client.call(method, params, { signal: controller.signal });
      clearTimeout(timeout);
      return result;
    } catch (error) {
      clearTimeout(timeout);
      if (attempt === retries - 1) throw error;
      const delay = Math.pow(2, attempt) * 1000;
      console.log(`Attempt ${attempt + 1} failed: ${error.message}. Retrying in ${delay}ms`);
      await sleep(delay);
    }
  }
}

async function healthCheck(client) {
  try {
    const chainId = await rpcWithRetry(client, 'sui_getChainIdentifier', []);
    console.log('Health check passed. Chain ID:', chainId);
    return true;
  } catch (error) {
    console.error('Health check failed:', error.message);
    return false;
  }
}

async function main() {
  const client = new SuiClient({ url: getFullnodeUrl('mainnet') });

  // Health check
  const healthy = await healthCheck(client);
  if (!healthy) {
    console.error('Endpoint is not healthy. Exiting.');
    process.exit(1);
  }

  // Example: get an object with retry and timeout
  const objectId = '0x0000000000000000000000000000000000000000000000000000000000000001';
  try {
    const result = await rpcWithRetry(client, 'sui_getObject', [objectId, { showType: true }]);
    console.log('Object data:', JSON.stringify(result, null, 2));
  } catch (error) {
    console.error('Failed to fetch object after retries:', error.message);
  }
}

main();

Fallos comunes y soluciones

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

Escenario 1: getTransactionBlock con opciones completas se agota. Solución: Establezca showInput: false, showEffects: false, showEvents: false a menos que los necesite. Si necesita efectos, considere obtenerlos por separado.

Escenario 2: getCoins con un límite grande se agota. Solución: Use un límite de 50-100 y pagine con nextCursor. O use multiGetCoins con una lista de IDs de objetos de moneda.

Escenario 3: getDynamicFields con un límite grande se agota. Solución: Reduzca el límite y pagine. Evite llamadas recursivas que obtengan todos los campos dinámicos anidados.

Escenario 4: Consultas de checkpoint con showContents: true se agotan. Solución: Establezca showContents: false si solo necesita el resumen del checkpoint.

Escenario 5: Todas las consultas se agotan, incluso las simples. Solución: Verifique su conexión de red, la salud del nodo y si el nodo está sincronizado. Considere cambiar a un endpoint diferente o usar un proveedor con mejor rendimiento (consulte nuestro artículo Latencia y rendimiento de Sui RPC).

  • Use siempre el objeto de opciones más pequeño que satisfaga sus necesidades.
  • La paginación es su amiga: nunca solicite más de 100 elementos a la vez.
  • Si un nodo es consistentemente lento, conmute a otro endpoint.

Compensaciones y limitaciones

Si bien gRPC ofrece mejor transmisión, requiere una configuración de cliente más compleja y puede no ser compatible con todos los proveedores. JSON-RPC es más simple pero más propenso a tiempos de espera en consultas pesadas. GraphQL es prometedor pero aún no es estable.

Los límites de QueryWeight no siempre están documentados con precisión; pueden variar según la configuración del nodo y el proveedor. Para límites específicos del proveedor, consulte su documentación. La página de precios de RPC de OnFinality proporciona detalles sobre nuestro servicio, pero no publicamos números específicos de latencia o rendimiento.

Los patrones de reintento pueden enmascarar problemas subyacentes. Si una consulta se agota consistentemente después de los reintentos, es mejor optimizar la consulta que aumentar el número de reintentos. Además, tenga en cuenta los límites de velocidad: reintentar demasiado agresivamente puede desencadenar limitación de velocidad, que es un problema diferente (consulte nuestro artículo Límites de velocidad de Sui RPC).

  • gRPC no es una bala de plata; requiere soporte del lado del cliente.
  • Los límites de QueryWeight no siempre son públicos; pruebe con su proveedor.
  • Los reintentos deben usarse para errores transitorios, no para consultas pesadas.

Próximos pasos y lecturas adicionales

Para aprovechar al máximo Sui RPC, comience implementando el patrón de reintento y reduciendo sus consultas. Si está construyendo una aplicación de producción, considere usar un proveedor de RPC confiable como el servicio de API de OnFinality, que ofrece alta disponibilidad y conmutación por error. También puede consultar nuestra guía de Sui RPC (Asistente de RPC) para consejos rápidos.

Para una comprensión más amplia de Sui, consulte nuestra página de red de Sui. Y no olvide explorar otros artículos en el centro de aprendizaje de OnFinality para más guías de solución de problemas.

  • Implemente tiempos de espera y reintentos en su código de cliente.
  • Optimice sus consultas para mantenerse dentro de los límites de QueryWeight.
  • Use un proveedor con múltiples endpoints para conmutación por error.
  • Monitoree el estado de sincronización y el rendimiento de su nodo.

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