Spring Tips: Reactive Summit Keynote: Here and There

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
first things first the community has matured right it's the point where now you can build uh practical applications in any technology you want and obviously i'm a big proponent of spring hence the t-shirt so i've got a couple of micro services here that we can look at i you know they're they're just trivial little micro services uh one of these is a customer's endpoint it's an http service that returns customer data so it's a record it has a field called id and a name yeah but what's cool in this example is that it's now just become easy to do the right thing which is to be reactive to not waste resources if we don't have to and so using that reactive code repository with a reactive controller that returns a flux it's just it's just now easy and every developer can now easily be reactive and that's what's cool right and it's familiar the only only telltale sign that we're doing something reactive as opposed to not reactive is we're returning a flux and we're using the reactive code repository otherwise this is exactly what you would have written using traditional blocking imperative io um but it's it's better you know okay so i've got some data in the database i created a schema sql to create a table called customer with a primary key and a name of our car and then i created data.sql and put both of these files in my source main resources folder and they just insert some record records into uh into the database of course guests uh first so i'll add i'll put you first so okay so that's up and running um and this endpoint you know i'm just i went to start that spring that i oh i've got start i've got the r2dbc support which is a reactive relational database connectivity abstraction so if you want to do reactive sql today the best bet uh is rtdbc because it connects to every uh there's a driver a reactive non-blocking driver for every technology you can you know every database you can imagine wanting to talk to and i'm using the embedded h2 implementation so that's up and running on port 8080 okay so you can see that here port 8080. again let's just restart it just right so this is reactive all the way down from the requests that come in all the way to the database and right that's great because why be reactive if you can't do it everywhere you know there's just not not as much benefit uh we need another system we need you know in order for this to be a little bit more fun it helps to have things to play with you know so we've got a custom endpoint uh for each customer they're gonna have a profile which is their you know maybe their name their registration date their their twitter information and so on so uh to describe that we've got a profiles service okay and this service is using our socket our socket was created by engineers at facebook and netflix and it was designed to solve some of the substantial limitations of http1.x http 2.x and grpc the whole point of our socket is to provide provide a binary protocol that surfaces uh the reactive streams as part of the network protocol itself so it's it reifies or makes real the concepts of reactive streams on the wire and it was actually built in part by rx java founder ben christensen right so it's a it's it's a very interesting protocol and i'm a big fan but obviously i'm a big fan i'm wearing the spring t-shirt and so on but you don't have to take my word for it there's some other small mom and pop organizations out there that are using it to great effect including like i said the aforementioned facebook but also alibaba right they're using it at scale along with spring and spring boot so this service is just a regular service i didn't even bother with an h2 database this time i just used the ultimate in memory database sorry test containers i use the ultimate in-memory database here just a map of customer ids scalable as you can get for a database right right yeah it's like the devinol of dbs devnet that's what this is basically um uh okay so var counter zero so for each customer and we only have two because it's just james and me then we increment the id we put a record in the database air quotes database uh create a new profile giving it assigning it an id and then a date for the registration right and um we can see that record described here we could have other fields but let's just keep it short and sweet and then we create an r socket endpoint here i'm using message mapping so you saw when i used http i did add controller and i used git mapping and so on well for our socket you're dealing with messages so we're using at message mapping which so it's not new but it it's purpose built for this kind of thing there's an end point here called profiles.custom id so given a customer id that's this thing right here uh we can give you the profile for that given that given customer right i'm returning it as a reactive stream a mono is like a completable future except it's got back pressure and it's reactive um and in that it produces at most one value earlier on you saw me returning a flux which is like a a stream except that it's reactive and it supports back pressure but they're both ultimately publishers okay so i've got my profile and i got my customer service one's using rsocket one's using http i think we need to build an edge service what do you think yeah i think we should have something that takes those two services and reactively uh exposes both of them right and combines them yeah composes them composing reactive services this is this is step i think we're doing kotlin yeah exactly kotlin's great uh obviously i have a choice you know this is the spring initializer start.spring io uh you have some choices here but they're really not they're not really choices right there's a choice of which version of java you'd like to use java 11 17 or 8 obviously among these three you've only got two real choices 17 or 11 and really if you're not involved in growl vm today i would just stick with john 17. so so i'm going to go ahead and create a new service here i'm going to use the reactive web support we're going to use the same r socket support from before and there's one other dependency i want right james you just suggested we okay we should expose this data right so uh to the world to make it accessible um but the problem is that that data is in different forms it comes in different shapes right it comes from an r socket endpoint and it comes from an http endpoint and there's a bit of a tension here we want small well isolated individual microservices but our clients want all that data in the same payload as fast as possible without having to constantly make chatty network calls and so rather than force each client to learn how to speak our socket and http and rather than having to redundantly impose security on both of those and rather than having to do the network calls all on the client we pass everything through the edge and the edge is kind of like a gateway to do cross-cutting kinds of network concerns and then we have that tension of well we want to create a view of the data for our client so one way we can do this is to use reactive api so i'll go back here to our code all right so we've got our basic data transfer objects now we need to build a uh some code to actually talk to the downstream services and we can't very well be expected to talk to them if we don't have a way to talk so we're going to create some clients well i use that term loosely here don't i mean i i want a client for the http uh service but for the r socket well it's just a socket it's about the server and plan it's got a duality yeah so our socket and when you say rsb our socket requester.builder equals rsb dot tcp and with rsocket you specify the the connection when you when you find the client so it starts up and it connects to the service and it stays connected and all subsequent requests are on that already connected multiplexed uh connection so you don't have to reconnect there's not that handshake the ack and all that stuff it's just faster and it's reactive because it's got an r at the beginning yeah so now for our rest client we're doing the web client which is the reactive web client built on top of nettie yep super fast you can use this and you should use this for all your networking you know http networking needs uh okay so there's my crm configuration now i'm going to build a a client right an actual thing that will give us access to our data in terms of the types of that service so we'll say crm client and in order to do our work we're going to inject in into the constructor and then stash into a private field the web client and the r socket requester okay so now we can create uh we have some methods here to in kotlin they call them member functions but you know whatever so okay we're going to say we want to have a function to return um let's get our customers and our profiles right right customers now we could do this the reactive way we could say http.get.urih localhost 8080 forward slash customers.retrieve.body2flux and the the return value that we expect here uh you know remember we're going to get an http json response i expect that to be turned into a reactive stream of customers and already we get some benefits by using kotlin i've got a member function that's returning or that the return type is implied to be a flux of customer but because we're using kotlin we have this nice so type inference so i don't need to specify the fact that i've got a flux of customer in more than one place so i can either do it um you know here in the return value or there explicitly in the terminating function a flux is great but it's a reactive type and it's in order to use it you very much you have to think about reactive data flow right you have to figure out how to chain things there's no sort of deterministic behavior unless you use the operators in the reactive api however to make it easier for people uh you know to kind of grok what's going on and to be able to think in the sort of imperative step one step two step three uh style to which people are have become accustomed to the last 25 odd years of of java there is co-routines right or there are covetings and kobi teams are awesome and you can use our integration with reactor with uh with these reactive types to automatically add functions through something called extension functions in kotlin you can add functions uh to change you know what you get from a a from a flex to a flow and i'll change this so a flow is kind of like a flux but it's a kotlin type right not the w till concurrent flow but the co-routines flow and that's great for a stream of values i don't need this anymore because it's implied by the type you know pseudo pseudoreified generics there we also want to create an end point here for the profile so profile for uh customer id int and this one is the r socket endpoint so we'll say route profiles dot cid passing in customer id and the uh the the data that we expect back uh we'll get it through a um a retrieve and a weight right so we'll say retrieve and await and profile so intellij is telling you there that when you call that you actually need to be in a suspend function to tell the compiler that uh that the thing is going to be async which is super cool because it needs a context it needs an async context now spring as the framework will provide that for you but you still have to mark your code accordingly so the compiler can kind of understand what's going to happen here um and then method now it just returns a profile yeah not a monolith profile just a profile the same magic is still happening behind the scenes your your your method's going to build on blogs yeah okay good cool some fancy inference there that um makes it super clean super clean all right now we want to compose these things we've got an r socket server and we've got a http server uh we want to get the data from both and get them into the same view for our client again the very common use case here is i've got different clients and they all have different uh bandwidth constraints quarks bugs protocols security etc so rather than forcing each client to learn about every single one of our downstream services they go to the edge service and they get uh you know usually it's a tailor-made edge service it's an image service just for android or just for ios or just for whatever and we can afford to build the endpoints that they need right so let's say suspend fun uh customer profiles and we need to actually build up a type of type customer profile so we'll say customer profile and we need to create a data type here to represent the composite of these two val customer on the left valve profile on the right all right so we say this dot customers dot map and then each you know we could use the implicit parameter here the implicit parameter is called it and it is automatically a pointer to type customer you can see that hint there in the ide but just to be very explicit here i'm going to name it customer so what i've got is a pointer to the current customer now i want to get the profile i'll say this dot profile for customer dot id okay and then i'm going to return a customer profile and response so i'll say customer on the left profile on the right and that's it that's the entire that's the whole game right there that's this is actually each element of customers and for those who go fetch the pro profile so this is a bunch of different requests that are happening or in the case of our socket messages and they're all non-blocking and this whole thing comes out as a giant composed non-blocking reactive operation right and i'm actually doing service i'm doing scatter gather service orchestration composition right i might you know launching many messages concurrently but you couldn't get simpler code i mean this is this is exactly the code you want it's very concise and yet it's also the most performant version of the code right uh so now we need to you know create an endpoint by which to consume this data so we can do this via http certainly so let's just create a controller here and http rest controller we'll say class crm rest controller private val crm crm client get mapping cos suspend fun customer profiles this.crm.customerprofiles okay let's just try that one that's our first our first uh cut if you will and this is going to start let's uh let's set up the port yeah thank you 8888 uh good okay so let's run that see what we get actually you know what rather than running it here because intellij doesn't love uh kotlin these days i'm not sure why we'll just do it on the command line so maven spring boot run i'd like to have consistency between my build tool and my things that i've done in my ide yeah so i just run everything from the build tool yeah makes sense okay well there we go there's there it is again i'm making as many requests as i can you can see it's looking at that calling so it's all composed together but all those requests that just happened are async non-blocking reactive super cool this is the customer data loaded first but as the first record for the customer data arrived we then called the profile service then the next record arrived then we called the profile service again but that didn't happen in a like it it didn't hit we didn't wait for the profile data for the first one to come back before we launched the profile request for the second one so there's no wasted block threads it's uh all reactive right it's concurrent as possible where the data flows as concise as possible as well okay good so this is great but we've got a what we have here is a custom view that we wrote for our client hopefully this is what they want this is the shape of the data that they need and we should be fine we should be able to go home for the weekend and enjoy but what about next week when some new client comes along and they want a new view of the data now we're back to square one and we need to build a new view and this is exactly the tension that facebook had in 2012 they realized that they wanted to have small isolated independent microservices but their clients need all the data co-located in the same process and the same payload as quickly as possible so they don't have to do redundant uh calls across the network for people that are on their low bandwidth devices traveling through tunnels right um and so they need they have a tension there it's a conflict the view the services should be well you know isolated and independent and teased apart but the clients want everything the way they want it in one shape in the same uh chunk so they created graphql to support that and we can do graphql and spring we can just add this spring graphql support but we don't have the spring initializer checkbox just yet so you have to manually as we did in the old days add a dependency to your build by copying and pasting the snapshot repositories here pasting that in there and then going to your dependencies and just manually adding the graphql dependency so graphql spring boot starter m3 maven reload okay so there's our uh new dependency now we're going to create a graphql controller you've seen an r socket controller you saw an http rest controller and now we're going to create another graphql controller it's the same annotation people don't realize that in spring the sanitation is actually part of the org spring framework stereotype package and it doesn't imply anything about http or our sockets or websockets whatever okay so uh crm graphql controller same idea same basic arrangement private val crm crm client and in graphql you have types right they have to define there's a schema so it's just built in it supports discoverability and introspection so you create a directory here called graphql and you create a file in there called schema.graphqls and there the root of all your graphql graphql services you have an endpoint um and those the numerated endpoints come from the query type and so i'm going to have an endpoint here called customer that gives me all the customer data well of course i need to have a type called customer and it has an id field and it has a name field now what also i also want the customer data to have access to all the profile data right so we'll create a new type here type profile and the profile has the id and it has the registered date but unfortunately while there is a built-in type for id there is no built-in type for dates so you have to just turn it into a string or create a scalar or something like that but for now we'll just create it we're going to have to represent them yeah so we're going to create a scalar so we're going to create a resolver so that when somebody asks for this field on this type a custom converter gets invoked okay a resolver and then same thing here for each customer i want to have the profile so i'll say profile now of course i want this all to be you know non-null right so we'll just add exclamation marks to all this stuff and this is great for tools that will do code generation based on the schema which is exactly what you want right it's you know consistency across the uh the boundaries yeah expressing nullability is great and when we're working in kotlin it's great because that information gets propagated into what we're doing in kotlin where we have the the explicit nullability support there too so okay first things first we want to create a let's let's say that we want to create a resolver for the registered date okay for the type called profile starting kind of lowest first so we create a handler method uh using schema mapping okay this is from the spring graphql project and the type here is profile and the field is the registered field so that's the name of the the function there i'm going to inject the root profile off of which we're working here and i'll say p dot register dot let's just do you know something horrible there you go that's not great you can do better use a simple date format or something like that but that'll work right so whenever somebody tr has a pointer to a profile and they ask for the result the registered field this handler method gets invoked okay great now what about our order data okay well i can do that here i can say schema mapping our customer data uh profile data i'm sorry yeah profile profile for the customer type i want to get the profile data right so profile c customer this dot crm dot profile four c dot id all right so suspend as always good okay so that's working anything that's not a built-in graphql type needs to be mapped right and we have specialized annotations for the case of the type that's a query because every program is going to have a query so rather than using schema mapping i mean you could you could say type name equals query and then fun uh customers you know and just return this dot crm.customers right and suspend i could do that but this is such a common thing and and by the way if you want to you can actually have field equals customers you know you can do that if you wanted but it's such a common thing to have a handler for a uh a type in the query type that we have an annotation called query mapping right so this evaluates ultimately to schema mapping with type query right and the nice thing about graphql is it's very consistent so i'm using uh query mapping there's also mutation mappings for updates there's um there's a subscription mapping for long lived updates like uh like um you know you've got stock trigger updates or feed or whatever that kind of stuff and mutations are great because there's no dogma there it's just you want to you want to change the state in the server you use a mutation there's no question about whether it's poster put or options or do you send a 201 or 200 or 202 or you know none of that it's just mutation that's it you either did an update or you didn't uh okay so cos that's still there right now we can go interrogate our graphql endpoint here we can go and interrogate our graphql endpoint here we get this nice little uh you know utility this dialog here and we can send a request we can say query and i get the customer data and i want to get the id and i can ask for that and that works just fine i've got the two ids and nothing more what about the name i want the name data good there's that okay what about the profile data okay well the profile data itself has it's made of constituent fields so i'll ask for the id and i'll ask for the registered and i get all that back now if i don't ask for registered you know if i just say give me that i don't get it and the resolver that we created to handle that conversion doesn't get invoked so you don't pay the cost for stuff you're not using it if you don't want the profile data and you don't want to incur the cost of making the call to the profile service then don't invoke it don't involve it and you won't get the data back but then again you won't pay the cost either right this is great for now so now you can use the same graphql endpoint to provide the you know the overview data for your you know overview page and then the details uh when you click on a particular record in the search results maybe you show the details right it's the same graphql endpoint it's very very consistent and the nice thing is that graphql as we support it in spring is reactive if you want it to be which i do uh or it supports imperative io but you know why would you do that go reactive yeah do the right thing or go core routines which is best of both worlds so great stuff right we've got really we we've got really nice primitives in the reactive apis to make make it easy for us to express code in a in a way that the scheduler can then optimize for us right and we can we can not we can avoid blocking at all turns we then looked at kotlin which takes it up uh which takes it up a notch and lets us write code in terms of uh of course teams which is even cleaner even more concise but again we're still getting the benefit of reactive programming and our in our understanding of these concepts cognitively has helped us go from reactive streams to cool routines uh and we're on the same page conceptually if we want to work with other people in other parts of the community okay okay uh i am recording my screen yes i um uh uh what else do i need to do i think i'm all good ready roll yeah so it's cool to see how the ecosystem around reactive has has grown to be massive and reactive is just everywhere the way that we kind of do everything now and all the frameworks languages are coming out with all sorts of different ways to support it and i spent a lot of time in scala and so i use a scholar library called xeo and we're going to now take the server that josh has written and exposed to us that edge server through graphql and that's of course all reactive all the way down but now let's build a reactive client to that server that's going to consume that data and do something interesting with it so josh is giving me his graphql file that defines the the graph of queries and types that i can use and so let's go and build a client for that thing there is a plugin that i'm using in this project that will take that graphql file and create the client-side stubs to interact with them and to do that i can just call this compile task and compile will will generate those different stubs for me so that's gonna take a minute to run because i'm doing a lot on my computer right now usually the scala compiler is a lot faster than that um yeah i've got slack actually mining some bitcoin in the background too that'll get you that'll slow things down considerably okay so let's go and create our query and so to do that don't worry about that compile error that's just because we um it generated the files that we need to continue so let's create our query so i'm going to use these generated files and i'm going to query the customers and then i can specify the fields that i want to get out of here let's do customer name and let's also get the customer profile so this is all type save sometimes i'm working in like this snapshot nightly snapshot of scala 3 which has given me a lot of great new language features and awesome stuff but it also means that intellij is not working yet super awesome so some of the tab completion stuff is not going to be working super well but okay so we're going to get a customer profile but then we have to tell it what we want to get in the customer profile so i can now just say profile.id so that's my query my graphql query now what i need to do is create a zeo application which is going to use the caliban librarian scala which is the graphql library and it's going to use zeo for the async unblocking the reactive piece of this uh which is you know gonna make the the request uh reactive underneath the covers and then zeo also does this great thing where it separates out the side effect the the effectful pieces of the application from the logic of the application so when i create my value app what i'm going to do is to find the logic of my program so what i need to do in app is i need to actually go and make a request a aj a graphql request so let's define our request and what it's going to be is i'm going to use the send method in caliban and then i'm going to take my query and i'm going to convert my query to a request and give it the server url to connect to so i can use the queries for they're composable so i can compose them together but in this case i want to kind of terminate that query or use it in a form of a request and send the request but what send is is send returns back to me as zeo so it's not actually going to do the work it's when i actually run it and zio applies the environment to the the logic of the program that it actually is going to end up making this request so when i make this request it is possible that the the request fails and so i um there's in a zeo uh i can have an air channel that will take the failure and put it into the type system of the zeo but i need to transform what i get back from the send method into that form normally when i call the send method i get back an ether which is either a error or a result and so i want to transform that that ether into just a zeo because the zeo can essentially has an ether built into it so to do that i'm going to call flat map on my xeo and i'm going to take a response not a request but a response and in my response what i'm going to do is i'm going to get the create a new zeo from an ether and then i'm going to give it the response dot body okay so now we have a zeo that can either either succeed or fail and based on what happens with the service now let's go and write our app so for our app we're gonna do this in a four comprehension because we're dealing with uh with async things and those are represented through uh things with flat maps on them or monads and as they're called and so what i'm going to do is i'm going to make my request so i'll make my request there and then i'm going to then use the put sterlin method to print out the body to string and then this program is going to yield no value so i'm going to just yield a unit there so that's my application and let's go and run this thing and see what happens so that's going to compile okay so now let's run this thing and see what happens we'll run it and that will compile and then run our client and it will go off make that graphql request of course reactively and then return the response so that's great looks like we got our list of james and josh now let's uh let's try this a couple more times because i actually had inserted something special into josh's code so that randomly when we make a call to customers we're going to fail because of course what he wrote was perfect and would never fail but i needed to add some failure into this thing so that we can see what happens when it fails so let's see if we can get lucky with our randomness and get this service to uh to fail that zeo when we make the request there we go looks like it failed okay so one of the cool things that we can do with a lot of these new paradigms that are reactive is add kind of stream steps to them to to change the stream change the uh the operations that we're doing the reactive operations that we're doing in some way so what i'm going to do with this request is now give it a retry so i'm going to tell it to retry this thing and i'm going to give it a schedule to retry with there's lots of different schedules you can use you can use time based ones or count based ones i'm going to do exponential back off and i'm going to start with a hundred milliseconds and then the default factor is two so it's just going to back off so now when i rerun this thing it should never fail because i have applied this retry logic to the request zeo and so just keep on retry retrying and of course i could set limits on how many retries at max i want to perform that sort of thing but we should never actually even if i get unlucky a bunch of times we should never actually get a failure we should always get a result out of this thing and so the cool thing with effect systems is that i have added this retry logic to the xeo which is just adding more information to the the application and then the zeo runtime is what actually takes this in a non-blocking reactive way actually does those retries and manages actually running this thing and doing performing the side effects okay so that was just another example of using scala and with a graphql client and of course reactive but a lot of similar paradigms between what we saw here and what josh did with reactor and with uh co-routines and with our socket so the cool thing is is that there's so much comp uh so much commonality now between the different ways to do reactive and really as people start down the happy path of programming they enter in usually now through reactive methods in a variety of different uh entry points so no matter where they're coming from they can be reactive reactive is everywhere and there's a common experience across all of them and i think that's what's super exciting in the reactive ecosystem right now is to see that commonality for how we do reactive programs just is the standard way to do things the sensible default and you see that you see the tenants behind reactive programming being embraced in in small parts or in large parts by by different languages and then that you know that perpetuates uh further into the ecosystem of libraries and so on so if you don't have interoperability at the api level you have it at the conceptual level already and that helps you start with other people's code you can integrate better you can focus on the business logic that matters instead of wondering whether this thing or that thing maps well enough to the other it just life becomes simpler when you can throw away all these different apis which are trying to express the same concepts right now you've got a few apis they're the foundation of your own code and you're able to just focus on the thing that matters building valuable software and getting into production awesome well hopefully that was helpful i'm excited about the future of reactive and the world going reactive so me too and thanks for everybody for joining
Info
Channel: SpringDeveloper
Views: 6,887
Rating: undefined out of 5
Keywords: Web Development (Interest), spring, pivotal, Web Application (Industry) Web Application Framework (Software Genre), Java (Programming Language), Spring Framework, Software Developer (Project Role), Java (Software), Weblogic, IBM WebSphere Application Server (Software), IBM WebSphere (Software), WildFly (Software), JBoss (Venture Funded Company), cloud foundry, spring boot, spring cloud
Id: uAb2NtRrxSk
Channel Id: undefined
Length: 34min 48sec (2088 seconds)
Published: Wed Nov 10 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.