Welche Faktoren haben dazu geführt, dass WAI Application fünf Mal umgestaltet wurde?

9

Ich habe neugierig auf WAI interface geschaut und während es einfach aussieht, war ich überrascht zu sehen, wie viele Iterationen es brauchte, um sich bei der aktuellen Form zu stabilisieren!

Ich hatte angenommen, dass der CPS-Stil für die Ressourcensicherheit die interessanteste Sache wäre, aber es sieht so aus, als gäbe es noch viel mehr zu lernen!

%Vor%

Einige Archäologie liefert etwas unbefriedigende Ergebnisse:

%Vor%     
sevo 27.11.2017, 18:58
quelle

1 Antwort

4

Alle Designs scheinen von drei Hauptanliegen getrieben zu sein:

  • Anfragen können gestreamte Körper haben (also müssen wir sie nicht alle im Speicher laden, bevor wir mit der Verarbeitung beginnen). Wie kann man es am besten darstellen?
  • Antworten können auch gestreamt werden. Wie kann man es am besten darstellen?
  • Wie kann sichergestellt werden, dass Ressourcen, die bei der Erstellung einer Antwort zugewiesen wurden, ordnungsgemäß freigegeben werden? (Wie kann beispielsweise sichergestellt werden, dass Dateizugriffsnummern nach dem Ausgeben einer Datei freigegeben werden?)
%Vor%

Diese Version verwendet iterates, was war eine frühe Lösung für das Streaming von Daten in Haskell. Iteratee-Konsumenten mussten auf "Push-basierte" Weise geschrieben werden, was wohl weniger natürlich war als die "Pull-basierten" Konsumenten, die in modernen Streaming-Bibliotheken verwendet werden.

Der gestreamte Körper der Anfrage wird dem iteratee zugeführt und wir erhalten einen Response -Wert am Ende. Das Response enthält einen Enumerator (eine Funktion, die gestreamte Antwortbytes an einen Antwort-iteratee liefert, der vom Server bereitgestellt wird). Vermutlich würde der Enumerator die Ressourcenzuweisung mit Funktionen wie bracket steuern.

%Vor%

Diese Version verwendet resourcet Monad-Transformer für die Ressourcenverwaltung, anstatt es im Enumerator zu tun. Es gibt einen speziellen Source Typ sowohl in Request als auch in Response , der gestreamte Daten verarbeitet (und was IMHO etwas schwer zu verstehen ist).

%Vor%

Diese Version verwendet die Streaming-Abstraktionen aus dem Conduit , vermeidet jedoch resource und bietet stattdessen eine Klammer wie responseSourceBracket Funktion zum Umgang mit Ressourcen in gestreamten Antworten.

> %Vor%

Diese Version wechselt zu einem fortsetzungsbasierten Ansatz, der es ermöglicht Die Handler-Funktion verwendet reguläre bracket -ähnliche Funktionen, um die Ressourcenzuweisung zu steuern. Zurück zum Anfang, in dieser Hinsicht!

Conduits werden nicht mehr zum Streaming verwendet. Jetzt gibt es eine einfache Request -> IO ByteString Funktion für Lesen von Brocken des Anfragekörpers und einer (Builder -> IO ()) -> IO () -> IO () Funktion in Response zum Generieren des Antwort-Streams. (Die Funktion Builder -> IO () write wird zusammen mit einer Flush-Aktion vom Server bereitgestellt.)

Wie bei den ressourcenbasierten Versionen und im Gegensatz zur iteratebasierten Version können Sie sich bei dieser Implementierung überlappen, indem Sie den Anfragetext mit dem Streamen der Antwort lesen.

Der polymorphe Handler ist ein netter Trick, um sicherzustellen, dass der Response-Callback Response -> IO b immer aufgerufen wird: Der Handler muss b zurückgeben, und die einzige Möglichkeit, einen zu erhalten, besteht darin, den Callback aufzurufen!

Diese polymorphe Lösung scheint einige Probleme verursacht zu haben (vielleicht beim Speichern von Handlern in Containern?) Anstatt Polymorphie zu verwenden, können wir ein ResponseReceived -Token ohne einen öffentlichen Konstruktor verwenden. Der Effekt ist der gleiche: Die einzige Möglichkeit für Handler-Code, das zurückzugebende Token zu erhalten, besteht darin, den Rückruf aufzurufen.

    
danidiaz 27.11.2017 21:45
quelle

Tags und Links