Frage

Ich entwickle eine App, die Anfragen an den Musicbrainz-Webservice stellt.Ich habe im Musicbrainz-Handbuch gelesen, dass man nicht mehr als eine Anfrage pro Sekunde an den Webservice stellen soll, sonst wird die Client-IP blockiert.

Welche Architektur schlagen Sie vor, um diese Einschränkung für den Service-Client transparent zu machen?

  • Ich möchte eine Methode aufrufen (zum Beispiel getAlbuns) und sie sollte die Anfrage erst 1 Sekunde nach der letzten Anfrage stellen.
  • Ich möchte auch 10 Anfragen gleichzeitig aufrufen und der Dienst sollte die Warteschlangen verwalten und die Ergebnisse zurückgeben, wenn sie verfügbar sind (nicht blockierend).

Danke!

War es hilfreich?

Lösung

Aufgrund der erforderlichen Verzögerung zwischen den Aufrufen würde ich a vorschlagen java.util.Timer oder java.util.concurrent.ScheduledThreadPoolExecutor. Timer ist sehr einfach und vollkommen ausreichend Das Anwendungsfall.Wenn jedoch später zusätzliche Planungsanforderungen identifiziert werden, ist ein einziger erforderlich Executor konnte mit allen umgehen.Verwenden Sie in beiden Fällen die Methode mit fester Verzögerung und nicht die Methode mit fester Rate.

Die wiederkehrende Aufgabe Umfragen eine gleichzeitige Warteschlange für ein Anforderungsobjekt.Liegt eine ausstehende Anfrage vor, führt die Aufgabe diese aus und gibt das Ergebnis über einen Callback zurück.Die Abfrage für den Dienst und der aufzurufende Rückruf sind Mitglieder des Anforderungsobjekts.

Die Anwendung behält einen Verweis auf die gemeinsam genutzte Warteschlange.Um eine Anfrage zu planen, fügen Sie sie einfach zur Warteschlange hinzu.


Nur zur Verdeutlichung: Wenn die Warteschlange leer ist, wenn die geplante Aufgabe ausgeführt wird, wird keine Anfrage gestellt.Der einfache Ansatz wäre, die Aufgabe einfach zu beenden, und der Planer ruft die Aufgabe eine Sekunde später auf, um sie erneut zu überprüfen.

Dies bedeutet jedoch, dass der Start einer Aufgabe bis zu einer Sekunde dauern kann, auch wenn in letzter Zeit keine Anfragen verarbeitet wurden.Wenn diese unnötige Latenz unerträglich ist, ist das Schreiben eines eigenen Threads der Verwendung wahrscheinlich vorzuziehen Timer oder ScheduledThreadPoolExecutor.In Ihrer eigenen Zeitschleife haben Sie mehr Kontrolle über die Planung, wenn Sie eine leere Warteschlange blockieren, bis eine Anfrage verfügbar ist.Es ist nicht garantiert, dass die integrierten Timer eine volle Sekunde nach der vorherigen Ausführung warten fertig;Sie planen im Allgemeinen relativ zum Start Zeitpunkt der Aufgabe.

Wenn Sie an diesen zweiten Fall denken, ist Ihr run() Die Methode enthält eine Schleife.Jede Iteration beginnt mit Blockierung in der Warteschlange, bis eine Anfrage eingeht, und notieren Sie dann die Zeit.Nach Bearbeitung der Anfrage wird die Uhrzeit erneut überprüft.Wenn der Zeitunterschied weniger als eine Sekunde beträgt, schlafen für den Rest.Bei diesem Setup wird davon ausgegangen, dass zwischen dem Start einer Anfrage und der nächsten eine Verzögerung von einer Sekunde erforderlich ist.Wenn eine Verzögerung zwischen dem Ende einer Anfrage und der nächsten erforderlich ist, müssen Sie die Zeit nicht überprüfen;schlafe einfach eine Sekunde.

Beachten Sie außerdem, dass der Dienst möglicherweise mehrere Abfragen in einer einzigen Anfrage akzeptieren kann, was den Overhead reduzieren würde.Wenn dies der Fall ist, nutzen Sie dies aus, indem Sie es blockieren take() für das erste Element, dann using poll(), möglicherweise mit einer sehr kurzen Blockierungszeit (ca. 5 ms), um zu sehen, ob die Anwendung weitere Anfragen stellt.In diesem Fall können diese in einer einzigen Anfrage an den Dienst gebündelt werden.Wenn queue ist ein BlockingQueue<? extends Request>, es könnte etwa so aussehen:

    Collection<Request> bundle = new ArrayList<Request>();
    bundle.add(queue.take());
    while (bundle.size() < BUNDLE_MAX) {
      Request req = queue.poll(EXTRA, TimeUnit.MILLISECONDS);
      if (req == null)
        break;
      bundle.add(req);
    }
    /* Now make one service request with contents of "bundle". */

Andere Tipps

Sie müssen einen lokalen "Proxy -Service" definieren, den Ihre lokalen Kunden anrufen.

Der örtliche Proxy erhält Anfragen und gibt sie an den realen Service weiter. Aber nur um eine Nachricht pro Sekunde.

Wie Sie dies tun, hängt sehr von der Tecnoligy ab, die Ihnen zur Verfügung steht.

Am einfachsten wäre ein Mutithread -Java -Service mit einer statischen und synchronisierten lastrachsten Zeit lang.

Ein ausgefeilterer Service könnte Arbeiter -Threads haben, die die Anfragen empfangen und sie in eine Warteschlange mit einem einzigen Thread platzieren, der die Anfragen aufnimmt und an den realen Dienst weitergibt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top