Wie filtere ich URLs mit existierenden Daten und achte dabei auf die Request-Rate?

  • Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

Tabula_Rasa

Mitglied
12 Mai 2017
195
2
18
Hallo zusammen,

ich versuche seit einiger Zeit Daten von einer API geliefert zu bekommen, die maximal 50 Anfragen/Minute erlaubt.
Ich muss mit einer Request-Chain arbeiten, auch wenn man es vermeiden sollte.

Code:
Promise.all(
orders.map(order => this.api.getURL(order.resource_url).catch(() => null))
).then(responses => {
  const successfulResponses = responses.filter(response => response != null)
  for(let data of successfulResponses) {
       // hier folgt eine Request-Chain mithilfe von data
  }
});
Der GET-Request:

Code:
  constructor(private http: HttpClient) {
    setInterval(()=>{
      this.time--;
      if (this.time === 0){
         this.time = 60;
         this.maxReq = 50;
      }
   }, 1000);
  }


  sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }


getURL(url: string){
    this.maxReq -= 1;
    if(this.maxReq <= 0){
        let restZeit = 60 - this.time;
        await this.sleep(restZeit*1000);
       return this.http.get(url, this.httpOptions).toPromise();
    } else {
        return this.http.get(url, this.httpOptions).toPromise();
   }
}
Irgendwie funktioniert es nicht so wie ich es mir vorstelle.
Also wenn 50 Anfragen erreicht wurde, warte ich die restliche Zeit ab und fahre danach wie gehabt fort - so zumindest mein Gedanke.
Aber das mit dem Warten klappt nicht ganz, da ich am Ende dennoch zu viele Anfragen schicke.
 
Zuletzt bearbeitet:

Tronjer

Moderator
Teammitglied
Moderator
8 Oktober 2010
5.184
468
83
Berlin
Wozu setInterval? Du brauchst einen counter, der hochzählt und einen timestamp, der beim ersten Request angelegt wird. Beides speicherst du in einer Variablen oder im localStorage.

Bei jedem folgenden Request vergleichst du den timestamp mit der aktuellen Zeit und fragst, ob mindestens 60s vergangen sind. Falls ja, Request ausführen und counter zurücksetzen. Falls nein, counter abfragen und Request durchführen oder blocken.
 
  • Like
Reaktionen: Tabula_Rasa

Tabula_Rasa

Mitglied
12 Mai 2017
195
2
18
Wozu setInterval? Du brauchst einen counter, der hochzählt und einen timestamp, der beim ersten Request angelegt wird. Beides speicherst du in einer Variablen oder im localStorage.

Bei jedem folgenden Request vergleichst du den timestamp mit der aktuellen Zeit und fragst, ob mindestens 60s vergangen sind. Falls ja, Request ausführen und counter zurücksetzen. Falls nein, counter abfragen und Request durchführen oder blocken.
Das ist eine gute Idee. Ich habe das Gefühl, da wird trotzdem ein Fehler auftreten. Ich verstehe das mit der Asynchronität nicht ganz. Wenn ich sleep() sage möchte ich, dass komplett alles aussetzt und nicht im Hintergrund irgendwelche Requests hin- und hergesendet werden. Naja, ich versuche es mal mit LocalStorage und wenn es nicht ganz klappt, melde ich mich hier noch einmal!
 

Tronjer

Moderator
Teammitglied
Moderator
8 Oktober 2010
5.184
468
83
Berlin
Wenn du innerhalb einer Funktion await aufrufst, sollte sie auch ein async haben.

Außerdem: Wenn du vorhast, dich näher mit JS zu beschäftigen, mache das gleich in Form eines Frontend Frameworks: Angular, React oder Vue.
 
  • Like
Reaktionen: Tabula_Rasa

Tabula_Rasa

Mitglied
12 Mai 2017
195
2
18
Wenn du innerhalb einer Funktion await aufrufst, sollte sie auch ein async haben.

Außerdem: Wenn du vorhast, dich näher mit JS zu beschäftigen, mache das gleich in Form eines Frontend Frameworks: Angular, React oder Vue.
Momentan beschäftige ich mich mit Angular. Ich habe gleich mal eine Frage:
Im ersten oberen Code-Abschnitt filtere ich die URLs raus, die 404 Errors anzeigen würden, deshalb mappe ich die Order und schau, ob deren URL auch Daten liefern. Das Problem ist, dass ich über 50 Order überprüfen müsste, was nicht geht wegen der Begrenzung, aber auch wenn ich sleep in meinem service.component.ts in der Funktion getURL() aufrufe, wird der Code im order.component.ts weiterhin ausgeführt... Packe ich zum Beispiel console.log("Fertig"); ganz ans Ende, erscheint "Fertig" in der Console, obwohl im service.component.ts auf meine sleep-Funktion gewartet wird.
 

Tronjer

Moderator
Teammitglied
Moderator
8 Oktober 2010
5.184
468
83
Berlin
Der gesamte Ansatz ist unschön. Anstatt etliche Requests in einer Loop aufzurufen, solltest du einen Endpoint erstellen, der nur einen Request benötigt. setInterval gehört nicht in den Constructor, und du kannst dir auch das Promise-Gedöns schenken. Angular setzt auf Observables.
 
  • Like
Reaktionen: Tabula_Rasa

Tabula_Rasa

Mitglied
12 Mai 2017
195
2
18
Der gesamte Ansatz ist unschön. Anstatt etliche Requests in einer Loop aufzurufen, solltest du einen Endpoint erstellen, der nur einen Request benötigt. setInterval gehört nicht in den Constructor, und du kannst dir auch das Promise-Gedöns schenken. Angular setzt auf Observables.
Ja, das finde ich auch, aber es handelt sich um eine externe Api, auf die ich leider keinen Einfluss habe.
 

Tronjer

Moderator
Teammitglied
Moderator
8 Oktober 2010
5.184
468
83
Berlin
Du kannst dir aber zumindest die Umformung der Response zum Promise sparen. Der http Client von Angular liefert Observables.
 
  • Like
Reaktionen: Tabula_Rasa
Werbung: