Apollo-link-rest: Manière élégante de mettre en file d'attente les demandes de serveur de repos ? Concurrence max, distance de temps, throttling 🚙⟷🚕⟷🚗 ?

Créé le 20 janv. 2019  ·  7Commentaires  ·  Source: apollographql/apollo-link-rest

J'utilise apollo-link-rest pour créer des appels vers une API de repos tierce gratuite. Je pense que c'est un excellent cas d'utilisation.

Cependant, comme nous le savons tous, les API tierces doivent être traitées avec _respect en ce qui concerne la simultanéité des demandes et les écarts de sécurité minimaux entre les demandes d'API successives_. C'est-à-dire en vous assurant que vous ne frappez pas le serveur plus souvent que toutes les 100 ms.

Alors qu'Apollo prend en charge les appels, je me demandais s'il y avait un bon moyen de répartir les appels dans le temps ? Par accident, il ne faut pas grand-chose pour créer une requête qui déclenche des requêtes supplémentaires pour résoudre la requête complète. Par exemple en utilisant la directive @export .

_Deux appels à la fois_ 🚀🚀

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
      }
    }
  }
`;

Pour atténuer les cas légers du problème de requête n+1 (c'est-à-dire récupérer tous les produits, puis la description de chaque produit), j'aimerais pouvoir disposer d'un filet de sécurité pour les erreurs du serveur 429 (échec en raison de la limitation du débit du serveur).

_Ce que je fais en ce moment : Wrapping fetch_

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 ce moment, j'encapsule le processus d'extraction dans une logique de file d'attente personnalisée, mais existe-t-il un "moyen plus élégant" pour l'intégrer ? Je suis sûr que de nombreuses personnes seraient intéressées par un certain contrôle de la charge sortante sans nécessairement échouer immédiatement dans les requêtes.

Commentaire le plus utile

Peut-être que je devrais ajouter ce que je fais en ce moment pour d'autres personnes venant de google. En ce moment, j'utilise 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)
})

// (...)

Tous les 7 commentaires

Peut-être que je devrais ajouter ce que je fais en ce moment pour d'autres personnes venant de google. En ce moment, j'utilise 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 J'allais suggérer customFetch, mais vous l'avez déjà fait !

Je ne suis pas sûr que cela devrait vraiment être une fonctionnalité directement configurable d'Apollo-link-rest, mais je soutiendrais l'inclusion d'un extrait comme celui-ci dans la documentation.

Pouvez-vous m'indiquer un endroit agréable dans la doc pour communiquer ces informations comme exemple de ce que l'on peut faire avec customFetch ? Je pense que tu as raison; jeter une telle configurabilité dans apollo-link-rest couplerait des méthodologies de récupération qui ne sont pas très élégantes.

Dans le PR, j'éliminerais p-queue pour un exemple plus artificiel pour les novices qui lisent. Quiconque utilise sérieusement apollo-link-rest comme médicament d'entrée dans GraphQL aura besoin d'une certaine gestion de la concurrence / anti-rebond à un moment donné.

@D1no , vous pouvez trouver les documents ici . Je suggérerais qu'il se trouve dans l'en-tête Options , au-dessus de Complete options .

Merci @tombarton. En examinant à nouveau le problème de plus près, ce pourrait être une bonne idée de pouvoir de toute façon avoir une option d'accélérateur simple pour l'appel de récupération.

Bien que j'aie dit à l'origine son couplage, ce n'est pas vrai. C'est l'appel à (toute arbitraire) une méthodologie d'extraction qui sévit ici. Pour pouvoir apprivoiser apollo-link-rest aveuglément / exécution avide, une simple option de concurrence et de limite de ms comme vu ci -

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

et/ou pouvoir le préciser dans la requête

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
      }
    }
  }
`;

Après tout, pourquoi une méthodologie d'extraction devrait-elle gérer la fréquence à laquelle elle est appelée (elle ne devrait pas se soucier de ce qui se passe à l'étage). Je vais y réfléchir un peu. De toute façon, customFetch devrait recevoir des informations sur la requête en cours et pas seulement une requête vide (pour pouvoir prendre des décisions intelligentes si les gens en ont vraiment besoin).

Peut-être que l'un des responsables/personnel (@fbartho) peut intervenir ? Je serais heureux de prendre le temps d'un PR si son mérite est approuvé.

@D1no J'ai honnêtement aimé votre suggestion d'inclure dans les documents. -- La file d'attente est à l'opposé de la façon dont nous voulions faire les choses dans l'application de notre entreprise. (La déduplication était celle que j'ai construite, par exemple).

Séparément, étant donné que les points de terminaison peuvent être totalement différents, j'hésite à définir "maxConcurrency/minThrottle" comme préoccupations globales.

ApolloLinkRest consiste à "connecter des éléments à Apollo" - ces problèmes que vous avez décrits semblent vraiment devoir se situer au niveau de la couche réseau, c'est-à-dire de la récupération personnalisée. -- De plus, je trouve peu probable que vous souhaitiez personnaliser ces valeurs pour chaque chemin de requête, donc l'intégration de leurs paramètres dans le GraphQL semble bruyante.

Très bien - Je vais d'abord ajouter un ajout à la documentation. Nous devrions d'abord toucher le fond de customFetch avant de crémer des couches dessus.

Cette page vous a été utile?
0 / 5 - 0 notes