Apollo-link-rest: ¿Una forma elegante de poner en cola las solicitudes del servidor de descanso? Simultaneidad máxima, distancia de tiempo, estrangulamiento 🚙⟷🚕⟷🚗?

Creado en 20 ene. 2019  ·  7Comentarios  ·  Fuente: apollographql/apollo-link-rest

Estoy usando apollo-link-rest para construir llamadas a una api rest de terceros gratuita. Creo que es un gran caso de uso.

Sin embargo, como todos sabemos, las API de terceros deben manejarse con _respeto en lo que respecta a la concurrencia de solicitudes y las brechas mínimas de seguridad entre las sucesivas solicitudes de API_. Es decir, asegurándote de acceder al servidor no más a menudo que cada 100 ms.

Mientras apolo se hace cargo de las llamadas, me preguntaba si hay una buena manera de distribuir las llamadas a lo largo del tiempo . Por accidente, no se necesita mucho para crear una consulta que active solicitudes adicionales para resolver la solicitud completa. Por ejemplo, usando la directiva @export .

_Dos llamadas a la vez_ 🚀🚀

const QUERY = gql`
  query RestData($email: String!) {
    # 1) Query for user 🚀
    users @rest(path: '/users/email?{args.email}', method: 'GET', type: 'User') {
      id @export(as: "id")
      firstName
      lastName
      # 2) Sub query for friends fires immediately as well 🚀
      friends @rest(path: '/friends/{exportVariables.id}', type: '[User]') {
        firstName
        lastName
      }
    }
  }
`;

Para mitigar los casos livianos del problema de consulta n + 1 (es decir, buscar todos los productos, después de la descripción de cada producto), me gustaría poder tener una red de seguridad para los errores del servidor 429 (fallar debido a la limitación de velocidad del servidor).

_Lo que hago ahora: envolviendo la búsqueda_

const restProviders = new RestLink({
  endpoints: {
    mySlowEndpoint: baseUrl
  },
  customFetch: (...args) =>
    new Promise((resolve, reject) => {
      // 🚙⟷🚕⟷🚗 Implementing my queue logic to fire of fetches
        resolve(fetch(...args));
      // when enough time has elapsed. 🚙⟷🚕⟷🚗 
    })
})

En este momento estoy envolviendo el proceso de búsqueda en una lógica de cola personalizada, pero ¿hay una "forma más elegante" de integrar esto? Estoy seguro de que a muchas personas les interesaría tener cierto control de la carga saliente sin que necesariamente las consultas fallen de inmediato.

Comentario más útil

Tal vez debería agregar lo que hago ahora mismo para otras personas que vienen de Google. Ahora mismo uso p-throttle ( repo ).

// (...)
import pThrottle from "p-throttle";

const restProviders = new RestLink({
  endpoints: {
    mySlowEndpoint: baseUrl
  },
  // Throttle fetches to max 1 concurrent request 🚀 and
  //  min. delay of 0.5 seconds 🚙⟷🚕⟷🚗 .
  customFetch: pThrottle( (...args) => {
    return fetch(...args);
  }, 1, 500)
})

// (...)

Todos 7 comentarios

Tal vez debería agregar lo que hago ahora mismo para otras personas que vienen de Google. Ahora mismo uso p-throttle ( repo ).

// (...)
import pThrottle from "p-throttle";

const restProviders = new RestLink({
  endpoints: {
    mySlowEndpoint: baseUrl
  },
  // Throttle fetches to max 1 concurrent request 🚀 and
  //  min. delay of 0.5 seconds 🚙⟷🚕⟷🚗 .
  customFetch: pThrottle( (...args) => {
    return fetch(...args);
  }, 1, 500)
})

// (...)

@ D1no Iba a sugerir customFetch, ¡pero ya lo hiciste!

No estoy seguro de que esto realmente deba ser una característica directamente configurable de Apollo-link-rest, pero apoyaría la inclusión de un fragmento como este en los documentos.

¿Puede indicarme un lugar agradable en el documento para PR esta información como un ejemplo de lo que se puede hacer con customFetch? Creo que tienes razón; lanzar configurabilidad como esa en apollo-link-rest acoplaría metodologías de búsqueda que no es muy elegante.

En las relaciones públicas, eliminaría p-queue para obtener un ejemplo más elaborado para los principiantes que lean. Cualquiera que utilice en serio apollo-link-rest como un fármaco de entrada a GraphQL tendrá la necesidad de _algunas gestiones de concurrencia / eliminación de rebotes_ en algún momento.

Hola @ D1no , puedes encontrar los documentos aquí . Sugeriría que se ubique en el encabezado Options , por encima de Complete options .

Gracias @tombarton. Mirando más de cerca el problema nuevamente, podría ser una buena idea poder tener una opción de aceleración simple para la llamada de búsqueda de todos modos.

Aunque originalmente dije que se trataba de un acoplamiento, en realidad eso no es cierto. Es la llamada a la metodología de búsqueda (arbitraria) lo que se está extendiendo aquí. Para poder domesticar la ejecución de apollo-link-rest a ciegas / ansiosa, alguna opción simple de concurrencia y límite de ms como se ve arriba , podría no ser una mala idea al final.

const restProviders = new RestLink({
  endpoints: {
    mySlowEndpoint: baseUrl
  },
  maxConcurrency: 2 // Max Concurrency 🚀🚀
  minThrottle: 500 // Handling Rate Limit in ms 🚙⟷🚕⟷🚗 
})

y / o poder especificarlo en la consulta

const QUERY = gql`
  query RestData($email: String!) {
    users @rest(path: '/users/email?{args.email}', method: 'GET', type: 'User') {
      id @export(as: "id")
      firstName
      lastName
      # NEW:       ⤥ 🚙⟷🚕     ⤥ 🚀🚀
      friends @rest(throttle: 500, concurrency: 2, path: '/friends/{exportVariables.id}', type: '[User]') {
        firstName
        lastName
      }
    }
  }
`;

Después de todo, ¿por qué una metodología de búsqueda debería administrar la frecuencia con la que se llama (no debería importarle lo que esté sucediendo arriba)? Pensaré un poco en eso. De todos modos, customFetch debería recibir información sobre la consulta actual y no solo una solicitud en blanco (para poder tomar decisiones inteligentes si las personas realmente lo necesitan).

¿Quizás uno de los mantenedores / personal (@fbartho) pueda contribuir? Me complacería tomarme el tiempo para hacer un PR si se aprueba su mérito.

@ D1no Honestamente, me gustó tu sugerencia de incluirla en los documentos. - Hacer cola es lo opuesto a la forma en que queríamos hacer las cosas en la aplicación de nuestra empresa. (La deduplicación fue una que construí, por ejemplo).

Por separado, debido a que los puntos finales pueden ser totalmente diferentes, dudo en establecer "maxConcurrency / minThrottle" como preocupaciones globales.

ApolloLinkRest se trata de "conectar cosas a Apollo": estas preocupaciones que ha estado describiendo realmente se sienten como si deberían estar en la capa de red, también conocida como búsqueda personalizada. - Además, me parece poco probable que desee personalizar estos valores para cada ruta de consulta, por lo que incrustar sus configuraciones en GraphQL parece ruidoso.

Muy bien, primero haré una adición a la documentación. Debemos tocar fondo customFetch primero antes de poner capas encima.

¿Fue útil esta página
0 / 5 - 0 calificaciones