Apollo-link-rest: Elegante Möglichkeit, Serveranfragen in die Warteschlange zu stellen? Max. Parallelität, Zeitabstand, Drosselung 🚙⟷🚕⟷🚗 ?

Erstellt am 20. Jan. 2019  ·  7Kommentare  ·  Quelle: apollographql/apollo-link-rest

Ich verwende apollo-link-rest, um Aufrufe an eine kostenlose Rest-API von Drittanbietern zu erstellen. Ich denke, dass es ein großartiger Anwendungsfall ist.

Wie wir jedoch alle wissen, sollten APIs von Drittanbietern mit _Respekt in Bezug auf die Parallelität von Anfragen und minimale Sicherheitslücken zwischen aufeinanderfolgenden API-Anfragen_ behandelt werden. Dh sicherstellen, dass Sie den Server nicht häufiger als alle 100 ms erreichen.

Da apollo die Anrufe übernimmt, habe ich mich gefragt, ob es eine schöne Möglichkeit gibt , Anrufe über die Zeit zu @export .

_Zwei Anrufe gleichzeitig_

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

Um leichte Fälle des n+1-Abfrageproblems zu

_Was ich gerade mache: 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. 🚙⟷🚕⟷🚗 
    })
})

Im Moment verpacke ich den Abrufprozess in eine benutzerdefinierte Warteschlangenlogik, aber gibt es eine "elegantere Möglichkeit", dies zu integrieren? Ich bin sicher, viele Leute würden daran interessiert sein, eine gewisse Kontrolle über die ausgehende Last zu haben, ohne dass Abfragen unbedingt sofort fehlschlagen.

Hilfreichster Kommentar

Vielleicht sollte ich hinzufügen, was ich gerade für andere Leute mache, die von Google kommen. Im Moment verwende ich 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)
})

// (...)

Alle 7 Kommentare

Vielleicht sollte ich hinzufügen, was ich gerade für andere Leute mache, die von Google kommen. Im Moment verwende ich 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 Ich wollte customFetch vorschlagen, aber das hast du bereits getan!

Ich bin mir nicht sicher, ob dies wirklich eine direkt konfigurierbare Funktion von Apollo-link-rest sein sollte, aber ich würde es unterstützen, einen solchen Ausschnitt in die Dokumentation aufzunehmen.

Können Sie mir eine schöne Stelle im Dokument zeigen, um diese Informationen als Beispiel dafür zu veröffentlichen, was man mit customFetch machen kann? Ich glaube, Du hast recht; Das Einwerfen einer solchen Konfigurierbarkeit in apollo-link-rest würde Abrufmethoden koppeln, was nicht sehr elegant ist.

In der PR würde ich p-Warteschlange für ein ausgeklügelteres Beispiel für Anfänger rausschmeißen. Jeder, der apollo-link-rest ernsthaft als Gateway-Droge in GraphQL einsetzt, wird irgendwann _einige Verwaltung der Parallelität / Entprellung_ benötigen.

Hey @D1no , du findest die Dokumente hier . Ich würde vorschlagen, dass es in der Überschrift Options über Complete options .

Danke @tombarton. Wenn man sich das Problem noch einmal genauer ansieht, könnte es eine gute Idee sein, trotzdem eine einfache Drosselungsoption für den Abrufaufruf zu haben.

Obwohl ich ursprünglich gesagt habe, dass es sich um einen Kopplungsabruf handelt, stimmt das tatsächlich nicht. Es ist der Aufruf zu (jeder willkürlichen) Abrufmethode, der hier weit verbreitet ist. Um apollo-link-rest blind / eifrig zu zähmen, sind einige einfache Parallelitäts- und MS-Limit-Optionen wie oben gezeigt am Ende vielleicht keine so schlechte Idee.

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

und/oder in der Abfrage angeben zu können

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

Warum sollte schließlich eine Abrufmethode verwalten, wie oft sie aufgerufen wird (es sollte sich nicht darum kümmern, was oben vor sich geht). Ich werde ein wenig darüber nachdenken. Auf jeden Fall sollte customFetch Informationen über die aktuelle Abfrage erhalten und nicht nur eine leere Anfrage (um kluge Entscheidungen treffen zu können, wenn es wirklich nötig ist).

Vielleicht kann einer der Betreuer / Mitarbeiter (@fbartho) einspringen? Ich nehme mir gerne die Zeit für eine PR, wenn ihr Verdienst bestätigt wird.

@D1no Ich mochte Ihren Vorschlag, in die Dokumente

Da Endpunkte völlig unterschiedlich sein können, zögere ich, "maxConcurrency/minThrottle" als globale Bedenken festzulegen.

Bei ApolloLinkRest geht es darum, "Sachen an Apollo anzuschließen" - diese Bedenken, die Sie beschrieben haben, fühlen sich wirklich so an, als ob sie auf der Netzwerkebene liegen sollten, auch bekannt als benutzerdefinierter Abruf. -- Außerdem halte ich es für unwahrscheinlich, dass Sie diese Werte für jeden Abfragepfad anpassen möchten, daher scheint es verrauscht, ihre Einstellungen in GraphQL einzubetten.

In Ordnung – ich werde zuerst eine Ergänzung zur Dokumentation veröffentlichen. Wir sollten zuerst customFetch durchfahren, bevor wir Schichten darüber streichen.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen