Inleiding tot Finagle

1. Overzicht

In deze tutorial zullen we een korte blik werpen op Finagle, de RPC-bibliotheek van Twitter.

We zullen het gebruiken om een ​​eenvoudige client en server te bouwen.

2. Bouwstenen

Voordat we ingaan op de implementatie, moeten we de basisconcepten kennen die we zullen gebruiken om onze applicatie te bouwen. Ze zijn algemeen bekend, maar kunnen in de wereld van Finagle een iets andere betekenis hebben.

2.1. Diensten

Services zijn functies die worden vertegenwoordigd door klassen die verzoeken aannemen en een Toekomst met het uiteindelijke resultaat van de bewerking of informatie over de storing.

2.2. Filters

Filters zijn ook functies. Ze nemen een verzoek en een service aan, voeren enkele bewerkingen uit op het verzoek, geven het door aan de service en voeren enkele bewerkingen uit op het resulterende Toekomst, en uiteindelijk terug te keren naar de finale Toekomst. We kunnen ze beschouwen als aspecten, omdat ze logica kunnen implementeren die plaatsvindt rond de uitvoering van een functie en de invoer en uitvoer ervan kunnen wijzigen.

2.3. Futures

Futures vertegenwoordigen de uiteindelijke resultaten van de asynchrone bewerkingen. Ze kunnen zich in een van de drie staten bevinden: in behandeling, geslaagd of mislukt.

3. Dienst

Eerst implementeren we een eenvoudige HTTP-begroetingsservice. Het neemt de naamparameter uit het verzoek, reageert en voegt het gebruikelijke "Hallo" -bericht toe.

Om dit te doen, moeten we een klasse maken die de samenvatting uitbreidt Onderhoud klas uit de Finagle-bibliotheek, het implementeren van zijn van toepassing zijn methode.

Wat we doen, lijkt op het implementeren van een functionele interface. Interessant is echter dat we die specifieke functie niet echt kunnen gebruiken omdat Finagle is geschreven in Scala en we profiteren van de Java-Scala-interoperabiliteit:

public class GreetingService breidt Service uit {@Override public Future apply (Request request) {String greeting = "Hallo" + request.getParam ("name"); Reader reader = Reader.fromBuf (nieuwe Buf.ByteArray (greeting.getBytes (), 0, greeting.length ())); return Future.value (Response.apply (request.version (), Status.Ok (), reader)); }}

4. Filter

Vervolgens schrijven we een filter dat enkele gegevens over het verzoek naar de console zal loggen. Gelijkwaardig aan Onderhoud, we zullen moeten implementeren Filter‘S van toepassing zijn methode die een verzoek accepteert en een Toekomst response, maar deze keer neemt het ook de service als de tweede parameter.

De basis Filter class heeft vier type-parameters, maar heel vaak hoeven we de soorten verzoeken en antwoorden in het filter niet te wijzigen.

Daarvoor gebruiken we de SimpleFilter dat de vier typeparameters in twee samenvoegt. We zullen wat informatie uit het verzoek afdrukken en dan gewoon het van toepassing zijn methode van de geleverde dienst:

openbare klasse LogFilter breidt SimpleFilter uit {@Override openbaar Toekomstige toepassing (verzoekverzoek, service) {logger.info ("Verzoek host:" + request.host (). getOrElse (() -> "")); logger.info ("Verzoekparams:"); request.getParams (). forEach (entry -> logger.info ("\ t" + entry.getKey () + ":" + entry.getValue ())); retourservice. solliciteren (verzoek); }} 

5. Server

Nu kunnen we de service en het filter gebruiken om een ​​server te bouwen die daadwerkelijk naar verzoeken luistert en deze verwerkt.

We voorzien deze server van een service die zowel ons filter als onze service bevat die is gekoppeld aan het en dan methode:

Service serverService = nieuwe LogFilter (). AndThen (nieuwe GreetingService ()); Http.serve (": 8080", serverService);

6. Klant

Ten slotte hebben we een client nodig om een ​​verzoek naar onze server te sturen.

Daarvoor maken we een HTTP-service met behulp van de handige nieuweService methode van Finagle's Http klasse. Het is rechtstreeks verantwoordelijk voor het verzenden van het verzoek.

Bovendien gebruiken we hetzelfde logboekfilter dat we eerder hebben geïmplementeerd en koppelen we het aan de HTTP-service. Dan hoeven we alleen maar de van toepassing zijn methode.

Die laatste bewerking is asynchroon en de uiteindelijke resultaten worden opgeslagen in het Toekomst voorbeeld. Hier kunnen we op wachten Toekomst om te slagen of te falen, maar dat zou een blokkerende operatie zijn en we willen het misschien vermijden. In plaats daarvan kunnen we een callback implementeren die moet worden geactiveerd wanneer de Toekomst slaagt:

Service clientService = nieuw LogFilter (). En dan (Http.newService (": 8080")); Request request = Request.apply (Method.Get (), "/? Name = John"); request.host ("localhost"); Toekomstige reactie = clientService.apply (verzoek); Await.result (antwoord .onSuccess (r -> {assertEquals ("Hallo John", r.getContentString ()); return BoxedUnit.UNIT;}) .onFailure (r -> {throw new RuntimeException (r);})) ;

Merk op dat we terugkeren BoxedUnit.UNIT. Terugkeren Eenheid is de manier waarop de Scala ermee omgaat leegte methoden, dus we doen het hier om de interoperabiliteit te behouden.

7. Samenvatting

In deze tutorial hebben we geleerd hoe we een eenvoudige HTTP-server en een client kunnen bouwen met Finagle, en hoe we communicatie tussen beide tot stand kunnen brengen en berichten kunnen uitwisselen.

Zoals altijd is de broncode met alle voorbeelden te vinden op GitHub.