Fault Handling with Polly and .NET 6

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
if at first you don't succeed try try again sage words words that were passed down to me from my parents encouraging me to retry something if i failed in the first instance very appropriate for today's video because today we're going to be looking at how we can retry requests when we initially get a failure result and in order to do that we're going to look at something called poly [Music] well hello wherever you are whenever you are where am i melbourne australia as usual and when is it it's january 2022 so yes this is the first video of the new year first video of season five so i'm very excited of course to be here back on youtube with all you lovely people so thank you for joining me here today so yes as i said in the introduction today we're going to be looking at transient fault handling and specifically we're going to be using uh the poly library in order to build policies by which we can deal with transient faults so it's a very interesting video i think i love paulie i think it's a great great library and in fact for those of you who have watched my micro services course this is one of the things there's a few things in that course that just given the length of it and time and things like that i didn't put into the course and this would be in my top five things that i would have if i was going to redo the course which i probably will do at some point this is one of the things i wish i had put into that course something about dealing with transient faults so that's actually why i made this video because it's almost like a an addendum to my micro services course so it's definitely if you're interested in that type of stuff it's definitely worth watching hopefully you find it interesting other than that uh let's get on with the video but again just a bit of a call to action as usual you know if you like the video please give it a like it just helps my analytics of course and if you haven't done so already please think about subscribing to the channel and you'll be notified of all new content that i will be putting out this year and i've actually got some really really exciting stuff this year next video is going to be good but the one after that can't say anything about it too much but it's going to be it's going to be a good one so i recommend you subscribe you'll be notified when that is available other than that again thank you for joining me and i hope you enjoy this video on poly all right so yeah welcome to episode one of season five and today we're going to be looking at fault handling or more correctly transient fault handling with something called poly and the.net 6 framework so this is what we're going to cover we'll look at what transient faults are and we'll give some examples of those we'll look at the policies that can be used to handle transient faults now if you don't really understand what we mean in this context by policy don't worry i'll i'll clarify that in a couple of slides time and then for the most part the main part of this video is we're going to use something called poly the poly framework to implement policies within.net to deal with transient faults if you want to follow along with today's video you will need to download the version 6 of the.net framework and it's the sdk that you will need and it's free vs code free again you can use any text editor or ide that you like but this video i'll be using vs code and then an api client to test we're going to actually build two very small services and in order just to test those services throwing errors and stuff like that we'll use a client api client you can use postman or in my case i'm going to be using insomnia irrespective either of those tools are free and there are other tools as well if you have something you prefer but i recommend insomnia it's got a nice interface cool so before we move on to the technical stuff let's just take a quick look at the definition of the word transient and as you can see on screen it's defined as something that lasts only for a short period of time or is impermanent okay so it's not a long-lasting thing it's not something that's permanent it's something that just has a short duration so that's what we mean by transient so let's just take a look at some examples of transient faults so as the name would suggest transient faults are fault occurrences that just exist for a short period of time okay they're not long lasting so some examples would be a network connection network being down so for example a router is rebooting or something of that nature so when you make your original request to a remote endpoint you may get failure response or no response whereas once the router has fully spun itself up and you requested that resource again you may you may get a successful response and what we're doing in today's video is dealing with that type of scenario where the original request failed but we want to try and invoke a successful outcome a microservice starting up so again kind of talking a lot about microservice distributed applications in today's video again you might be wanting to talk or get information or whatever from a distributed service that service may not be available at the time you make the original request make a request again and you may or may not get a successful response or a server refusing connections due to connection pool exhaustion so maybe everybody in a company is logging into the email server at nine o'clock in the morning and maybe some people get connection errors because it's just too many people trying to connect in at that point you try again in a few minutes you may be successful so again you know the type of faults we're talking about here are occurrences that are impermanent that may not occur again if you tried it again in a short period of time in the future so why do we care but why can't we just make a request fail and go well that failed and move on with our lives well yeah i mean that is one way of dealing with faults but if handled correctly rather than just getting an error response and accepting that failure initially we could eventually get a successful response so something i like to think about is if you're building an e-commerce application and you have an order placement service and you know that service when it tries to create an order maybe the first time round fails by and large you don't want to just accept that failure and and say sorry that order could not be placed number one that's an incredibly bad customer experience number two it's going to hit your bottom line so you want to try that again you want to try and create that order again in the hope that this time succeeds and again for obvious reasons it's better customer experience and of course it's going to positively impact your bottom line as well so you don't want to just walk away and accept failure again important point to note is sometimes the fault might not be that transient and you might just get a failure response which again you have to figure out some way of dealing with that which might be some kind of other process that you run to deal with non-transient type faults and again you know when you're talking about distributed applications microservices type architectures the likelihood of a transient fault occurring just because there are so many moving parts on so many different systems maintained by so many different people the likelihood of a transient type fault occurring is definitely there and so you really need to think about a way of handling that should occur and that's really what today's video is about so handling transient faults so we're in today's video we're going to be focusing on the retry policy so again it's probably a policy or a concept that you'll be very familiar with it's not that complex and when we think about the retry policy or retrying generally what we're going to do we're just going to retry again and again and again you know for a period of time or possibly infinitely and so when we talk about the retry policy we can configure things like how many times do we want to retry do we want to retry forever possibly there may be a scenario where you do want to do that or in other cases you may not want to do that and just retry for a finite period of time so we're going to do that today's video we're going to play with that level the other thing you can configure with the retry policy is the interval in between retrying so you get a failure response do you retry immediately or do you wait and how long do you wait for so again we're going to play with that in today's video so we're going to be working with the retry policy but we're going to have three flavors of the retry policy and i'll take you through those now so policy number one again all retry policy but this one is the immediate retry immediately retrying for five times so we're going to build two services we're going to build a request service very simple.net six service and a response service we're actually going to build the response service first and the response service is going to be super simple it's just going to be one endpoint and when we make a request to that endpoint some of the time it's going to succeed gives our 200 http 200 okay some of the time it's going to give us a 500 a server error response and the whole point of these videos how do we handle that and retry that should that occur so two services we're going to build step by step in today's video request service and respond service and it's in the request service that we're going to do our work with polly so let's take a look at this first policy and this is immediate retry for five times so we will make our original request to the response service and let's just say for example this is just one of many scenarios that could play out we get a failure response back from the response service in this policy we're going to immediately retry again denoted by the green arrow that's we try attempt number one so original response in black is sort of the original request in black the original the subsequent retry first we trying green you will then get uh again this is just a scenario that i'm playing out here we'll get a failure response and we'll then immediately retry for a second time third time fourth time fifth time and then you can see that we've had five retries one original request five retries and unfortunately in this case if we tried immediately on those failure responses and the last response we get is a failure at that point we stop we say time out this just failed we tried but we failed what we're going to hope happens if we kind of wind back the clock a little bit let's say we retry uh three times or we have a third we try request what we're hoping again no point in this is that we do eventually get a successful response this is another way this policy could play out a scenario using this policy could play out and we actually get a successful response on our third retry attempt and then what i'm trying to show here is from the perspective of the request service although this is technically not actually correct but to all intents and purposes and you'll see this play out it will almost almost look like we make our original request and we just get back a successful response that's kind of how it'll look under the covers obviously that's not what's happening that our actual retries occurring but from the purposes of the request service it kind of looks as a level of abstraction it looks like it was a request and a successful response and that's kind of the power and the beauty of something like polly policy number two very similar retry five times but rather than immediately retry on failure we're going to wait and this kind of makes sense because you know and again you know using the example of a network server or rebooting or a router rebooting the chances are if you try immediately five times probably you're going to get that failure scenario and just fail out you're more likely to succeed if you do wait a bit of time in between requests and so this second policy we're going to wait a constant period of time between failure responses and in this case i'll just pick three seconds again we've got two services we'll make our original request we'll get a failure response we will wait three seconds before we retry again we try again or make our this will be our first retry let's say we get a failure response we'll wait a further three seconds before we retry again and in this case we're going to say that you get a successful response on our second retry again could still play out to failure doesn't matter so that's our second policy still retry but we're waiting a constant period of time in between retries and then finally our third policy and this is the one you're probably when you're talking about retry policy this is the one you're going to hear about most probably in the real in the real world which is retry with exponential back off and the idea this policy is you wait longer and longer and longer between me trying on failure responses in an exponential fashion okay so again just to give you an example and the numbers i'm using here are just example numbers we'll make our original request we'll get a failure response we'll wait for example one second before retrying again we'll get a failure response we'll wait three seconds this time in between retrying again we'll retry again we'll get a failure response wait even longer period of time five seconds before we retry again and then again in this scenario we get a success but this this could play out that you wait longer and longer again you'll retry five times so you can see with these policies you can tweak those two levels how many times do you retry and how often or what's the time frame in between retrying and depending on the type of scenarios you're thinking and you may want to play around with those levels i'm going to implement all three of these policies in today's video all right so just before we go into coding i just want to cover off what is poly so it is basically the de facto resilience and transient fault handling it's a bit of a mouthful but basically if you want to do transient fault handling there are alternatives but you're probably more than likely going to be using police very very widely used we can use poly to create policies in organic apps and there's a number of ways you can create policies in poly again about the mouthful i'm going to define a class based approach there are other approaches you can take using like a dictionary and stuff like that but today we're going to use a define a class that represents our policies in this video it's really this is a this is a beginner's video this is like an on-ramp video uh to get you started there are other policies on top of retry that you can start to play with that we're not covering today things like circuit breaker timeout and bulkhead isolation and all of those are actually detailed on the poly website and the github site again today's video bit of an on-ramp bit background get you working with retry and then it should give you a good grounding in which to move forward and start playing around with these other uh policy types so with that that's enough theory and introduction i think we start coding up our solution all right so let's start coding so i'm just going to open a new instance of visual studio code which will probably start on my other window let me just pull that over and the first thing we're going to build is our response service so if you remember from the walkthrough which was not that long ago we have a request service which we will do next and that's where all our poly stuff is going to be first of all we're going to do a response service and all it's going to give us is an endpoint that we can call a http get endpoint and some of the time that's going to give us a successful response a 200 http 200 response and some of the time it's going to give us a 500 server error response other than that that's all we really care about and when we get the error response we're then going to use poly to invoke our retry policy so that's it very simple very straightforward so in visual studio code not visual visual studio code i'm going to hit control and backtick to open the integrated terminal and move into my working directory which in my case is called season 5 and into episode 1. yours will be different or you can of course follow that aiming convention if you like first i'm going to check is the version of.net that i have installed so net dash dash version and it should be six and i really recommend you use six for this video if you use an earlier version of the framework you'll you'll still get it working but there are some quite big differences between the earlier versions of the framework and version 6. next thing we're going to do having confirmed that we have dot net 6 install is scaffold up a web api project so dot net new the name of our template which is web api and then the name of our project we're just going to call it response surface hit enter and that will go away and scaffold up for us our response service project just before we move on to anything else if you do a dot net new dash dash list that will give you a list of all the potential templates that you could use to scaffold up other project types and if we scroll up you'll see we just picked this one here web api but there are plenty other ones to pick from just thought i'd mention that but let's just clear that do a directory listing and we can see we have a response service project so we type code response service dash r that's going to open the response service project in this instance of visual studio code fantastic and we'll probably get a little warning here saying we need to rebuild some resources there we go just click yes this is a project so probably the first thing we want to do is just make sure it's working so dot net run and this is dot net six and one of the things you'll notice for those of you who are used to using earlier versions of the framework is the port numbers for both https and http are different to what would usually be there so last previous version of framework http would always be 5000 at least initially and https was always 5001 and if we scaffolded up another project you would have those values as well you'd have to go in and change them if you had those two services running at the same time otherwise would be a poor conflict what they've done in dot net six is change that and they provide you with a kind of semi-randomized port number which is quite nice but just just different so i thought just call that out and what we have in our project which we're basically going to delete is we have a model well a forecast model just with some weather temperature type data and a controller or where the forecast controller and all it does is just basically return back that data so randomized data so we can try and have a look at that if you want just to see how that works so i'm going to copy the https endpoint again this is really just checking that we have everything wired up correctly and if you just hit the controller there are four cast assuming a spell that correctly yeah we just get a json response back with some temperature data so that's all looking okay we're going to get rid of that we're not using that at all so we're going to do that next just before we move on though just a couple of quick observations on dot net six if you've not used it before you'll notice there's no startup class everything is now done in the program class uh taking me a little bit of time getting used to it i don't like change too much but again it's you do the same stuff you configure your services here and you also configure the request pipeline down here all done within the program file and there's not even a main method or anything like that now if you if you really miss the startup class like i do you can reintroduce one if you really want to do that but again microsoft have done this just to kind of simplify things the other observation just very very very quickly is the inclusion of this these nullable reference types uh it's a video all on its own but you will notice that um that will manifest certain things in your code that you may not be used to if you used earlier versions of the framework you have to think about null reference types this kind of forces you to think about null reference types much more which is not a bad thing it's a good thing actually but it does lead to some more complex coding decisions that you may not have encountered before again getting a little bit used to i kind of like it i kind of hate it but again just thought call out um if you're using dot net six for the first time if you've not used any other earlier versions of the framework you probably don't even know what i'm going on about my apologies for that but i did want to just cover some my very high level observations of some of the differences between earlier versions of the framework and this one anyway so our project's scaffolded up all we need to do now is just make some changes we're going to introduce a very simple controller basically that will provide us with our get endpoint so we'll do that next all right so back in our project i'm just going to get rid of some of the scaffolded code we no longer need so the first thing to go is this weather forecast model so right click and delete and we are actually going to use a controller but i'm going to get rid of this one rather than repurposing it we'll write one from scratch so you can see how that all works so delete that and we're good to go so yeah very simple service it's really just going to consist of one controller so a new file i'm going to call this response controller and i just want to make sure i'm spelling it correctly i have a propensity to not put in the r for some reason i don't know why don't know anyway define our namespace which is response service controllers don't forget this and then we're going to define our class so public class response controller and we're going to inherit from controller base which is yeah as the name would suggest a base cut a base class suitable for api type controllers now you can see it's complaining it doesn't know what that is so control period to bring in the using namespace of microsoft asp.net core mvc fantastic a couple other things to do just to wire up our controller class is we want to decorate it with api controller and that just gives us access to some default behaviors that you would expect of an api controller which is nice and then the other thing we need to specify is the route where can we find this controller and then subsequently where can we find the endpoints within this controller so route open brackets double quotes can be anything you like kind of standard convention certainly for rest apis is to term api sometimes people like to put versioning if you're versioning an api i'm not going to bother doing that today and what i'm going to do i could just specify it as response which is what we're going to do so you can do it like that or you can use the square brackets convention and put the word controller in this is where i need to make sure i spell it correctly and all that does is it looks at the name of the controller and it pulls out the name the this component of the controller so again naming convention for controllers.net would be the name followed by the word controller so if you had a controller that was returning a list of books it would be books controller or if it was authors it would be authors controller and this convention here the square brackets convention just takes this part of the name and that's what the root becomes or the route becomes that's cool so that's our kind of class defined and then we just want to start to specify our end point within that so it's an action result public action result give it anything any name we like and we're going to expect this to accept an integer i'll just call it id doesn't really matter and that id we're going to use to determine how often or not this endpoint is going to fail so the higher i think this is the way i've written it the higher the number the more likely it is to succeed so if you pass in a number between one and a hundred if the number is 100 it's pretty much going to succeed all the time if the number you pass in here is one it's pretty much going to fail all the time and if you pass something in between 50 for example then theoretically half the time it will succeed in half the time it will fail i think that's the way i've written it but we'll come on and write the code and you'll see how that works we're going to use our random class to generate a random number and compare the two but that wasn't clear as we write the code i think it will become a bit clearer but that's the reason behind this number it's just to allow us to tune the the likelihood of failure or if you're a glass half full kind of person the likelihood of success depends on it depends on your outlook on life doesn't it really so that's our action result we want to specify that it's a going to respond to get requests so http get and then we want to define the route to this particular action result so again use the route component open brackets double quotes curly brackets to denote the parameter that we're expecting and i'm just going to call it id so the route to this action result is going to be um basically an integer so with that in mind what we can actually specify is colon and then specify that we're expecting an integer type as opposed to a string or something so basically if you just put a comment in here this action result is going to respond to a get request and the route to it is going to be the server base url which is localhost 7000 and whatever api response and sum number doesn't matter what and it's going to be a number between 1 and 100 and if you pass in if you pass in the number of 100 then the likelihood of that given as a success response is going to be pretty much 100 if they pass in the number of one then it's likely we're going to get a failure response okay before we get on to that logic though i do just want to check that this is all wired up correctly because we could have made some mistakes somewhere so i'm just going to return an ok which is a 200 response so we'll save that off and we'll do a dotnet run and that's all run up okay and from the looks of it that's all one up okay yeah great and i'm going to use insomnia to call this endpoint so let me just select this and copy that and then we can move to insomnia and we're going to create this is just an empty environment i'm going to create a new request i'm going to call it call response service direct get request create that i'll paste in the base url then the route to our controller which is api response that will give us nothing because there are no action results or endpoints that match that so we get 404 not found if we then depend on an integer value that should give us a 200. okay so it's found that route find action result given us a 200 response so that's all looking pretty good fantastic so um the only other thing remaining in this service is just to build in a little bit of randomization logic that's going to dictate whether it returns a success or failure so we'll do that next so let me just stop our service from running and we don't have too much left to do it's actually very simple logic in here so inside our action results we're going to make use of the random class and we'll just call that rnd and we'll just new up an instance of that and then we're going to define a variable a random variable we'll just call it rnd integer and that's going to be a random number we'll use a random class next between um one and one hundred so or zero and one hundred so one two one or one i think that's correct all right so again we are passing in some number here we are going to generate an additional number here between you know it can be anything between 1 and 100 and what we're going to say is using a very simple if statement if the random number that was generated it could be anything is greater than or equal to the number that we've passed in then we're going to issue a failure response so again the higher the number that we pass in here uh the likely the more likely this is not going to be true okay the lower the number we pass in here so if you pass in one or two in here the likely of this random number being bigger than that is going to be greater and the more likely it is to fail so the bigger number we pass in our route will determine the likelihood of success or failure and the reason i'm doing that really is number one we want our servers to sometimes fail and sometimes succeed in a kind of random way although this is not truly random nonetheless for all intents and purposes it is uh and not only do we want it to succeed and fail sometimes but depending on the policy that you are using may dictate well the likelihood of failure may dictate the policy that you attempt to use okay so again this sets you up if you want to use some of the other policies you can play around with end points that fail all the time or fail most of the time or endpoints that fail only very rarely and you would tune your policy towards that as well anyway digressing slightly so how do we do this well before we do anything else let's just do a console nightline just so we can have a kind of log of what's going on and i'm just going to say failure and generate failure generate generated 500. okay and the way we do that is we're just going to return a status code and let me access status codes plural and we want status code 500. my eyes are going a bit crossed let's see if we can find it all right otherwise we are just going to return okay so that's fine i'm just going to copy this though so we have some kind of output that will tell us that it was successful fantastic so let's run this up and let's give it a go using insomnia again if we come back to insomnia so if we pass in a number one we are likely to see a 500 internal service error we do that again 500 keep doing it we're getting 500 if we pass in 100 we're gonna get success occasionally there we go we'll get a an error but most of the time it's going to be uh successful so i think if we pass in 101 i think we'll probably never get yeah there you go so we'll generate a number between 1 and 101 so we need to change that doesn't really matter so we're always getting um success so where it really becomes more useful as we pass in something at 25 that's saying it's going to fail 25 so it's going to succeed 25 percent of time more than likely it's going to fail so yeah most of the time we're getting failures and occasionally we'll get the odd 200 and that's exactly what we want when we come on to using poly to test these transient faults and we can work with this slider to say 50 to you know work half the time and fail half the time fantastic so that's looking pretty good it's doing pretty much what we want it to do so really we're going to come on to the really exciting part which is to write our request service um and use poly to deal with this random transient fault uh type scenario so we'll do that next all right so let's get started with our request service so i'm gonna open a new instance of visual studio code which opened on my other screen and as before integrated term also controlling backtick and i'll change into my working directory which is on my d drive in my season five folder and in episode one so doing a quick directory listing you'll see that i already have my response service that i'm going to create another project in here now to be honest with you don't really need to do that um it's not really a solution or anything it's just two completely separate projects but we'll keep it in the same place so as before net new it's a web api template and we're going to call this request service and that should scaffold that up quick directory listing looks good and then we will just see code request service dash r and that will open that project in visual studio code now again just to kind of label the point that i was talking about if we go let's click yes to that first if we look in our properties and can launch settings you'll see that the port allocation for this project is slightly different so there won't be a port conflict so quite like that as before we're just going to delete the scaffolded stuff that we don't need so we'll take it where the forecast class so we'll delete that and we will create our own controller but i'm going to take out this weather forecast controller for now and again we'll create our own one from scratch now just before we do that we do need to install a package dependency and i'm sure as you're probably guessing it's going to be something in the nature of poly or something so if we come over to nougat we do a search for poly you'll see the poly package there and you can see how many downloads it's at 162 million so it's you know it's pretty popular we're not going to install that one though we're actually going to install this one here microsoft extensions http poly because later on in the video we're going to be making use of a http client factory which is really the way you should be using a http client so because of that we're going to be using this package if we just click on that though you will actually and look at the dependencies of this package you'll see it does include the poly packages part of that anyway as well as the microsoft extensions http package as well so we're going to just install this so maybe if over here we may as well just copy this and we'll just run that our command line so back over in our project that we've just scaffolded up i'm going to open the cs proj file so we can see what we have by way of existing dependencies which is not that many apart from swashbuckle and i'm just going to paste in that command line now again you can specify a version i actually like to not do that and just take that out and get the latest version whatever that happens to be and in this case it should be uh yeah the one that was specified anyway 601 cool so that's us added our package reference which includes paulie so that's cool so we can kind of forget about that for the moment so all that really remains well it as a few things but just by way of scaffolding let's come back over to our controllers folder right click new file and we're going to call this request controller and the code is available on github if you don't fancy typing out there's not a lot of code involved in this project so i really would suggest you follow along um but if you want to download the code you can of course do that if you want to save a bit of time so request controller start with specifying our namespace and let's request controller dot controllers and i'm just double double checking my typing as i move along and i've already made a mistake it's not request controller it's request service that's namespace there you go we are creating a controller but the namespace is the name of our project which is request service so namespace request service controllers and then we just define our class as we have done before so public class request controller this time as before we're going to inherit from controller base and control periods to bring in right namespace which is uh microsoft asp.net core nbc fantastic as before we are going to specify that this is an api controller and we will also specify the route the default route as before i'm going to say api and then use the square bracket syntax and just put controller in here so that means the route to this controller is going to be api forward slash request fantastic okay and we want to create one action result and what we're going to do is we're going to call we're going to use this action result to call our other service our response service we're going to put that code in here that's going to call our other service and we're going to trigger that call by making a request to this endpoint so it's kind of like a chain of requests which actually i don't suggest you do in the real world but for the purposes of this video just to test paulie it's it's okay so again we're going to create an action result here we'll call that action result from insomnia and that action result will make a call to our response service and we'll see how all that kind of plays from there hopefully that makes sense so we're going to create an action result this time we're going to make it um an asynchronous action result because we're going to be making use of a synchronous method uh when we make our request our http request so we'll make this async it's going to return a task of type action result and we'll just call that make request and we're not going to pass anything in here we could i guess if we really wanted to pass in that id you know the id that we're using to kind of tune our success and failure rates i'm not going to bother here i'm just going to hard code it in here but if you want there's a bit of homework you can do that i'm just going to keep it kind of simple and i'm going to make this a get request i'm fairly sure if i didn't specify that this was a get request then that that's the default verb anyway so probably don't need to do that i think it's just good practice to do that so this route should be accessible using a get request get a comment and of api request that's it this should respond to this route here no need to put any ids or anything in all right fantastic and all i'm going to do just again as before just to test that we've got everything wired up correctly i'm just going to return an okay response just so we can test that this is this is working and we've not made any uh silly mistakes and i've not made any stupid mistakes now you'll see it's complaining because we've tagged it as async but we don't have any await calls in here we're not it's not really in a synchronous method it's just going to run synchronously and we'll get that warning but don't worry that will get cleared up as we move forward so yeah warning for the moment but not not to to worry too much about it right now so let's just do a net run and make sure that's all running get the warning that's okay and i'm just going to copy this and let's bring up insomnia again i'm going to create a new request i'm going to call this get call request service okay that's a get request create that we'll paste this in and put in the route which is api request okay and that should just give us an okay response it does fantastic very simple i just wanted to check that we've got everything wired up correctly so what we're going to do next uh we're going to let me just stop this running we're going to change our action result to make a call to our response service without paulie and we'll see how that manifests and no surprises we'll get back errors and so on so on and so forth and then we'll introduce paulie to deal with our transient falls so next we're going to update this just to make calls to a response service without paulie and we'll see what we get so we'll do that now all right so back in our action results let's move this down a bit just going to make sure that's stopped and i'm just going to take this out and we will put it back in in some form in a bit so the first thing i want to do is create a http client so our client the spelling's way off today equals new http client now as i was mentioning earlier we're going to be using a http client factory going forward to actually make or basically create http client instances um before we do that though we're going to do it in a more basic way which is by directly using http client in this way which is not the recommended way of using http client so i'm just calling that out we are going to change it going forward but for now we'll keep it simple we'll do it uh step by step this will all work fine for our purposes we're just calling that out so we've got our http client and all we're simply going to do is make our request to our response service um so we're going to create a variable to hold that response and this is where our weight statement comes in and we're going to wait on our client http client and we're going to use the get async method and we simply just pass in the url to our response service so if we come back down to insomnia and we come here we're just going to basically pass this in i'm going to change this to 25 just so we have it failing more often than not which seems to be the case yeah that's cool so copy this and we're just going to paste this in here now of course you know in the real world in production scenarios you're not going to be have hard-coded urls and all that kind of stuff i'm not going to deal with that in this video it's just going to make it too long i'm going to try and keep it a bit shorter today so we're just hard coding our endpoints in here in a real world dude this in config or whatever fantastic so we've got a response of some kind and based on the url we're calling here with the value of 25 we're going to expect it to fail more often than not so all we then want to do is just do a quick check on the response so if our response is success code so it's a http 200 let's say then we're just going to do a console.writeline rightline there we go trying to avoid typing my fingers aren't working very well today um and we're just going to say response service returned success tool tips are great but it can be a bit annoying we t yarned there we go returned and then we'll put the semicolon in at the end and we're just going to return okay fantastic and then i'll do an l statement probably don't actually need that l statement let's take that and we'll just put in anything else will be failure let's say so we'll just do a console right line in fact let's just copy this here saves me typing so if you're watching me typing and we'll just say failure great failure spelt wrong okay there we go that's right and then we're just going to return the status code status code let's write status codes plural and we'll just return to 500 as well i mean you would you know again in the real world you would you actually check to see what error was passed back properly by the other service you know it's going to be a 500 in this case so we'll just leave it like that let's tidy up that formatting there so i just did a control uh shift and f to format all right so that all looks good uh let's save that and let's run it up and what we should get i'm going to actually open this up here so we can see our console log and i'm going to open up our other running service as well just so you can see what's happening there it's on my other screen and what i'm going to do let me just pull it over here this is where the screen magnification can be a little bit problematic i'm just going to stop it i'm going to clear the screen and i'm going to run up again just so we have a nice uh clear window okay so this window here probably a bit difficult to see this is our response service and this is our request service and i'll bring up insomnia and let me minimize that what i might do actually is i'm going to make a call to our request service this one here i'm going to do off screen okay just so we can see what's happening here so click send and you can see here that's cool let me just bring it onto the screen so you can see what i got i got a failure back which is what we'd expect and you can see here that our response service generated a 500 failure and our request service got that response and it's saying the response service returned to failure so it's a kind of one-to-one pairing okay i'm going to click it again same thing click it again and you can see this time it happened to be a success so our response service issued a 200 and we got that back from um our request service okay need to watch my language so again just you know clicking that you can see there's a one-to-one mapping so anytime we make a direct request to our response service we get that back and so taking a look at our request service imagine this was a real world service and it's making requests to this other response service and it's for the most part you can see here look it had one success out of however many calls that is eight or eight or nine calls this is what we want to address we want to try and do something with this transient fall and retry in our case to try and get a successful response so that's really the whole point of what we're doing here and that's what we're going to do next so i'm going to stop this running now the request service and i'm going to introduce you to a policy or how you create policies using poly and we're going to create our very first policy which is a very simple immediate retry so let's do that next all right so i'm just going to stop this from running and make sure i'm in the right service and in the request service which is correct and yeah we're going to create our first policy now now there's a number of ways you can do this in using poly i'm going to create a class that will contain our policy definitions basically you can do it by using a dictionary there's a few ways you can do it and really it comes down to your own personal preference and what you're trying to achieve but i'm just going to use a class-based approach and check out the poly documentation if you want to have a look at how the dictionary approach is done so in our project i'm just going to right click create a new folder i'm going to call it policy policies should i say make sure that's capital p and then here i'm going to create a new file i'm going to call it i don't know what happened there new file i'm going to call it client policy dot cs and then we'll start with the namespace and we're in the request service and policies fantastic and we're just going to create a public class called client policy fantastic so the way we set up our policies is we do that ultimately through our class constructor but first before we even do that i'm going to define a property that will represent our policy so public async we'll have to bring in a name space here asy async retry policy of type http response message and we'll give it a name immediate [Applause] immediate http retry so as per the slide where we're just going to retry we're just going to retry immediately for five times if we get a failure message and we'll just specify that as a get using a set here so yeah we're getting an error so just ctrl period to bring in the using poly.retry namespace that should be good this is complaining because it's not being used as yet so we're going to change that now so let's create our class constructor that's ctor tab we don't need to pass any parameters in and then we're just going to set up our immediate retry policy by defining it so immediately try immediate http retry equals policy and i think we need to bring in another namespace poly using poly here we go so policy handle result of type http response message visual studio code's doing a lot of the hard work for us and then we're just going to define what that is so let's use a lambda expression say res goes to if the result is not hence the exclamation mark success code says status code then what do we want to do so when we've got response it's not a success code we want to retry asynchronously for five times and that's that's there and i think take that out it should get rid of that error there we go it's that simple that's our first policy basically so we've created a client policy class we have defined a immediate retry policy we're going to handle a response message which will be our http response code and we simply check to see whether it's successful or not and if it's not we just retry five times that's it basically we're not quite done yet though because we have a policy sure that's all fantastic but we are not using it yet so what we need to do now is go back into our controller method and actually use the policy with our http client now before we do that though we are going to be using constructor dependency injection so what we're effectively going to do is over in our controller we are going to inject in a client policy into this so we can make use of it so before we do that we actually need to wire it up in our configurable we don't actually have a configure services method anymore we just have our program class but you can see here in this section here this is where we add services to our dependency injection container so we're just going to do that now register our client policy uh with our container so we can inject it into our api controller and i'm just going to put this up here and so we make use of this builder server let me access our services as usual and then we are going to add a singleton of type client policy which is the policy class we've just set up and we're going to say new client policy [Applause] and i'll just run that off and give the semicolon and we need to bring this name space in so using request service policies so that's just registering or client policy in our dependency injection container so we will get an instance of that when we ask for it so let's just save that off and then back over in our controller we are going to inject that in to our controller so before we can do that as we're using constructor dependency injection we're going to have to create a control a sorry a constructor in our controller so ctor is a short code tab and into that we're going to pass a client policy class now we'll just call that client policy and it doesn't know where this is coming from so using request service policies and then the standard pattern we're going to create a private field called client policy i'll make that equal to client policy and just hang on a second we'll finish this off and i'll take you through this if this isn't entirely clear if you've not done much with dependency injection before what we need to do here if we do a control period is generate a read only field called underscore client policy so just to take you through this again we have created a policy class which is where we have our policies defined then within our program class we want to register that class so it's available for use using dependency injection we do that using this services ad singleton yeah and then finally in our controller we want to inject an instance of that into our controller class so we can use the policy and we do that is by defining a constructor in our in our class here and we inject an instance of client policy and so our dependency injection container will give us an instance of that and assign it to this here we want to then use that throughout the rest of our class the way we do that is using a private field which we define we actually define that up here and we assign whatever was injected to that private field so we can now use this underscore client policy uh instance to make use of our policy okay fantastic so now the magic happens so back down to where we made our request we're going to leave this for the moment so again we're just creating as before creating a new http client instead of directly calling our endpoint like this i'm going to just comment this out and we're basically going to call this but using our policy so i'm leaving it in here just as a comment so you can contrast and compare what we're going to do so again we'll just find the response and we'll say equals await this is where you make use of a client policy so underscore client policy dot and we only have one policy which is our immediate retry policy and then we say execute async all right and then we're going to actually then within execute async we're going to execute basically our call to our endpoint so let me take a new line here lambda expression and this is where we make use of a client and in fact what we can actually do here let me take this out i'm just going to copy this here exactly the same thing that we're doing here and i'm just going to paste that in here and don't forget to put semicolon in okay so we're really still doing this here ultimately we're still doing that but we're wrapping it around our client policy and it's going to take care of retrying for us five times that's it the rest of the controller remains exactly the same fantastic okay so this is the moment of truth what we are going to do now is let's run up we've got that run good no errors and we are going to bring over our other here's our let me stop this this is our response service i'm just going to stop it clear it and re-run it so we can see what's happening okay so at the top is our response service at the bottom is our request service and back over here is insomnia so again off screen i'm just going to make a call just for the purposes of keeping it looking clean i'll hit send and you can see what we have what happened to you it's quite interesting our response service originally gave a 500 failed what you can then see is a second call i've only clicked the button once by the way i've only made one request as you can see here and this time it just so happened to return a successful response as you can see here so we've had the original request and one retry and then down in our response service all we actually see is that the response service returned a success so let me do it again you can see here this time we got three failures so the original request two failures and then we eventually got a success but again from the perspective of the request service it looks like it's just been successful again and that is the power of poly and i'm sure you can agree when i first kind of started playing with this i just thought this was so cool i thought it was amazing that was excellent you got this dodgy service that most of the time is failing but from the perspective of our request service it looks okay now that's not to say that you won't eventually get a failure and if we if i hit this a few more times so you can see i'm still getting success which is quite amazing well there we go we do eventually in this instance here we do eventually get a failure there was one original request which was a 500 and then the five retries were also failures so you can see this was probably this here so the original request and then we have yeah five retries all of which were failures and so you do still get failures but you can see here um you know well actually down here you can see for the most part you're getting a lot more successes and that's by doing an immediate retry fantastic so what we're going to do next is we're going to play around with a couple more variations on on a theme this this is a bit um theoretical because again the way our service is set up it's immediately responding and that kind of stuff imagine in the real world you probably wouldn't want to immediately retry because you know for reasons we've gone through already services might be taking a while to start up so we're going to start looking at that i'm going to implement a retry policy but with a constant wait time and then finally one with a exponential back off wait time and then finally what we're going to do is we're going to make use of http client factory and refactor our code a little bit so it looks a lot neater and almost when you come to the controller you you'll actually look as if you're not even using poly at all we're going to do a lot of the config elsewhere so we'll do that towards the end of the video but next we're going to do two more variations in the policy just to get our heads rounded and then we'll use http client factory all right so back over in our request service i'm just going to stop this from running and come back into our client policy now we've done a lot of the wiring up here we don't we're going to change it slightly but yeah we're not the next few sections are going to be fairly brief we're just going to play around with this so i'm going to define another property and again i'm going to copy this for the most part just saves me typing and the only thing when it changes the name so rather than being immediate http we try i'm going to call this linear linear http we try so we're going to put a delay in between so underneath here we're going to just define linear retry and we're going to actually want to copy most of this as well because it's mostly the same and again it just saves you watching me type so we're going to the logic's effectively the same we're going to check to see what the response success code is if if it's not a success then we're going to yeah we're going to retry five times as we have done before but rather than retry async we're going to say wait and retry async and in here we're going to pass in some more parameters so we're going to say retry attempt goes to time span and we're just going to specify from a certain number of seconds and let's just say three seconds okay so hopefully should make sense instead of using the let's just take this on to the new line here actually what we should probably do to the period better convention there we go so first one which we've not changed i've just changed the formatting slightly we're going to retry five times this one we're going to retry five times but also we're using this wait and retry and we're specifying the number of seconds that we're going to take to retry all right that's simple all we then need to do is come back over to our controller and rather than using immediate retry here we're just going to change that to linear retry that's it so let's do a dotnet run [Applause] fantastic and what i'm going to do is also bring in the other service let me just kill it near the screen and run it and then i'm going to bring insomnia onto the screen now i'm actually going to bring insomnia onto the screen i'm just going to make it a bit smaller because what i want you to see is i'm hoping that it fails and i want you to see insomnia spinning a little bit spinning its feels a little bit i'm just trying to get this this is looking pretty horrible this is the problem with um low screen resolutions so what do we have over here this is our this is getting way too confusing this is our response controller so this is um let me get rid of this that's better let me get rid of this that's better okay so this is our response controller this is our request controller so we should see errors being generated then here all right so let's make a request you can see here it's wait we've got our first 500 and it's waiting three seconds and it's retrying five times you can see it's taking a while there we go so he had original requests uh and then three subs well four four retries the fourth one of which was successful but the point and again you can see from the purposes of our request service it was just a it looked like it was successful from our uh insomnia session where you could see how long it took it took 12.4 seconds this time because there was a wait period in between every request just try that again just want to kind of show you that again so we got failure we wait three retry we got another one so six seconds we retry again maybe try again and we may get a failure this time when we actually finally get a 200 of that's just fortunate anyway you get the idea so one of the things i want to call out here is that you know think about if would you want to use this if you were building a client based application making a request to something you probably wouldn't want to use that for obvious reasons it would be not particularly great user experience or somebody waiting with a spinner for like 15 seconds or whatever while you retried this is probably more suited to non-human interactive type application service to service communications where the user is shielded from this type of thing so just wanted to call that out you might not want to employ this type of thing where interactivity is your main concern but still a very useful retry policy serves to service the final one we're going to do is basically a variation of this one but we're just going to use exponential back off and the reason i'm including it is it's a very common pattern that you will see used out there in the real world where you you wait subsequently longer periods of time before you retry so we'll do that next and then finally we're going to just wrap everything up by using http client factory and you'll see why we do that and in addition to the benefits of using http client factory you'll see one of the other benefits of taking that approach here it makes our code look a lot cleaner inside our controller but first let's finish off our last policy and uh then come on to client factory all right so let's just minimize this stuff here make sure i am in the right space so yeah this is not the one we want this is the one we want here so we're back in our request service let me just bring up our file explorer that's cool and i'm going to stop this from running so back in our client policy class i'm just going to define another our last third and final policy which is our exponential back off and i'm actually just going to copy this again because we're just changing the name of it effectively and i'm going to call this one spell correctly and then i'm going to just copy this one here as well i don't like copying code but i've already typed this out kind of so i'm sure you don't want to see me typing it in again and we just want to give it the right names let me just copy this and i'll paste that in here cool and again it's wait and retry we're going to rate and retry five times we're going to still use a time span and from seconds but instead of specifying a linear constant value we're going to use math and then we'll use power and then a little simple formula uh to to the retry attempt okay and that's going to exponentially increase the time that we wait between failure responses effectively so let's just save that i think that control b control b just make sure there's no errors that looks okay let's do a dot let's do a dotnet run down here all right so i'm actually going to minimize this because we don't really need to see this we're going to use insomnia for the most part and then we're going to bring up our other service here and i'm just going to kill that clear it and then we run it so we have a cleaner window and then i'll bring up insomnia and we'll make a request so we get failure and we retried fairly quickly so let's try that again i want to get a few failures this time so we get failure we're waiting a few seconds we may get another failure we're going to wait longer period of time another failure we'll wait even longer well actually we haven't so i was wondering why that wasn't working it seems to be doing it fairly constantly we didn't change we didn't change the [Music] uh the use of the policy so let's come back over here we are still using it we didn't save that for a start there's a lot of things wrong here we didn't save that and we're still using the linear retry my goodness there we go not even been that long a video so i've got no excuses for making such stupid mistakes but hopefully if you spotted that that's good means you're getting the hang of what it is we're attempting to do so that's cool let me just stop that now just another thing i've been using.net run with net six you can do something called net watch which basically is this hot reload thing that you might have heard a lot about and actually opens up a web browser which we're not too bothered about but basically the idea behind using.net watch is we can make changes to our service while it's running and we don't need to stop it and restart it okay anyway just started calling that out so okay cool so we've saved that offer using exponential retry policy we have saved that off so let's try that again um okay this is our response service let's run that again and let's open insomnia and give this another go so again what we should see is we if we get a failure it should retry pretty quickly and then it'll get subsequently longer in between responses so failed definitely waiting longer before retrying i think it looks like it is anyway yeah so it's getting a third failure so yeah if it was linear retry it would be yes that's definitely working now you can see it's waiting a lot longer between retries include four three retries here and it's getting longer and longer between as you can see there between retries now one of the things you'll need to be maybe a success eventually but you can see that took 30 seconds for what were all what was ultimately four retries so again getting longer and longer one thing you do need to watch out for is that you can get timeouts and stuff like that so you can you have to be aware that you might need to tune when your request will eventually time out and again that's actually another policy type as well so a whole world here that can get opened up but again just giving you an introduction to the kind of stuff that you can do with it so that's exponential back off and you know typically with exponential backup i've seen it you know work you try the first four requests are fairly quick and then you know maybe do 10 retries but the distance between the 8th and 9th and 10th you try are really quite long periods of time really quite long periods of time anyway food for thought so that is basically paulie in a nutshell but what we're going to do in the last section is just we're going to stop using http client directly and use http client factory and we'll do a little bit refactoring just to tidy up our code so we'll do that next all right so we're going to use http client now and we're going to use it in its most basic basic way and again i'm going to cover well i'll cover it very briefly the reason you use http client factory is because using http client factory the basically the connection pool is managed if you just use individual http clients you really have to manage the the connections that that creates ultimately when you're making requests here there and everywhere and for making a lot of requests you can end up with basically connection exhaustion connection pool exhaustion whereas the client factory approach it manages the connection pool for you um and it's just basically the recommended way of using http clients so we're going to adopt that pattern point number one firstly just taking a really simple approach and then we're going to use it in a slightly nicer way with poly that means we can kind of take away the the use of using poly within the controller and move that code elsewhere anyway before we do that let's come back to our requests yeah we want our request service make sure we don't get too confused there we go our request service let's kill that from running so ctrl b just to bring up our explorer window and we're going to come over into our program class and quite simply all we're going to do is just use builder services and we're going to add http client okay and that just basically tells our yeah basically our dependency injection container that we want to use http client factory and just a quick fyi because we use this package reference here that actually includes the microsoft extensions http package that you need if you're going to be using a http client because it's included here we don't need to include it explicitly it's already there so step number one again this is a really basic use of http client factory we're just registering it in our program class we'll save that off and then back over i'm just going to kill this uh we don't need to use this we're not doing any more policies back over in our controller what we're going to do is we're going to inject uh that into here http client into our constructor and you'll see how that will manifest in a second so we're going to inject in that high http client factory and we're just going to call it underscore client factory and then down here underscore client factory equals actually that's not underscore here i'm just calling that client factory and let me try equal to client factory there we go and all we need to do is just create a private read-only field control period generate read-only field there we go so we have our read-only field called underscore client factory and that was basically assigned that gets assigned whatever is injected in through here okay so instead of doing this newing up the http client i'm just going to comment that out actually and come on to a new line and we're going to use our client factory instead to create our client so we'll save our client equals underscore client factory create client okay and it's that simple so basically we're using a client battery to create client and we're giving it assigning it to this client variable here and we continue to work with it as before so i'm going to take out exponential retry i'm just going to put it back to our immediate retry just for the purposes of time and let's just try that again and make sure it all works so dotnet run fantastic and i'll just bring up our other service bond service we need to get it to run.net run dot net run all right dot net run and fantastic and let's make a request and it should just uh work as before there we go so we've got uh original requests immediate retry failed and then immediately try it succeeded let's just try it again same thing okay so again we've got failure there so that's all cool um very simple we're just not using the client um http client directly we're using a client factory to create a client brilliant fantastic we could leave it at that but i want to take it one small step further again this is just an introductory video but i feel there's one last step we can do in using the client factory and that's to kind of move the use of the policy code and move it into our program class so it means basically anytime you use a client factory it's already assumed it's not assumed at all it's already using the policy that you can figure it with and so you don't actually have to explicitly use that in your controller code and this looks a lot nicer so last thing we're going to do let's do that next all right so this is our response service i'm going to get rid of that uh leave it running and this is our request service so actually one point i did forget to mention because we're now using a client factory you get all this additional logging information through using the client factory you can't turn it off but you know i just thought i'd mention that it's there so let me stop this from running for the moment and i will uh get rid of our command links we have a bit more let me get rid of the sidebar as well so just taking a look at the code so in our request controller it's all working it's all fine but what i want to try and get back to is slightly simpler looking code so rather than you know we want to make a request to our endpoint but rather than wrapping it around this client policy stuff what i ultimately want to get to is if we just comment this out and uncomment this this was our member this was our original way of making requests without polly okay but it looks a lot neater it looks a lot imagine we just got it i'm going to leave that there for a moment but imagine we move back to this method of doing things it's a lot cleaner looking it's not simpler looking and the idea is that we can hopefully configure our http client in one place and it means when we are using it in multiple controllers we only need to configure it potentially in one place or yeah in a centralized place so that's what we're attempting to do here so actually if i just save that off for the moment this is kind of regressing and slightly to the point where our request service is not using poly any longer so just to double check that let's do a dot net run and we'll bring up insomnia we should by and large for the most part get failures of every time we send this now because we're not using poly we will get the occasional success but for the most part we're getting failures as you can see we're not using poly we're just making requests directly to the service and because of the way it's configured for the most part it's going to error out so we'll leave the code like that in here for the moment there is one small change we will come back here and make but for the most part that is as done so it leads us to the point where okay where are we going to configure our client policy stuff in fact let's just be brave and take this out of here now we're not even going to use client policies and we'll get rid of this as well okay and that should be okay let me just check that again just want to make sure before we move any further that that's still uh still working okay and we'll just make a request yep still still working okay cool um so where do we configure our policy stuff well we configure it over in our program class where we basically set up our http client factory so ctrl b to bring up our browser and let's come over into the program class and let's just isolate where we are adding our http client we're going to do a little bit of work here now there are a number of ways you can work with http client factory you can use named clients which is what we're going to do here you can use typed clients all that kind of stuff so we're going to use what's called a named client so not my favorite approach but for the purpose of this explanation it's probably the simplest way of doing it so i'm just going to create a named client called test okay so http client factory uh called test and then to add our policy directly onto the client we simply tail on and add policy handler to that and we'll take a new line and then here we basically configure what our requests are going to have our requests are going to work with our policy class so against lambda expression we'll just call it anything like we call it request and it's a lander so and a request method if it's equivalent to http method get because all our requests are get methods at this point in time then we basically just configure the policy that you want to use and really do that is by saying new client policy which is our client policy class as i'm sure you'll do and then we just tell it which policy you want to use and i just want to use uh immediately try and then we just specify an alternative here we'll just use the same thing let's copy that paste it in here all right take that out and i think that should i think i've missed out something here yeah i missed the question mark there we go so yeah not not the most straightforward looking code but just to kind of review we are creating a named http client calling it test we're adding a policy handler and then we're just specifying that policy handler here and basically telling it that we want to attach this to get requests and then we're telling it which policy we want to use which is the immediate retry policy in this case and i just will get rid of that oh my goodness there we go so you can see the whole code there all right and again code is on github let me just save that off if you want to kind of go through the code there as well and all we need to do is when we come back to our controller class all we need to do is we just need to name the client so again back over here we called our named client test we just need to specify when we create the client block client type we want to use and this now should give us access to the poly policy fantastic so let's just do one last.net run and i'm going to bring up another service here i'm just going to kill that and i just realized generate spelt wrong but that doesn't really matter clear the screen and do a net run so we should see you know the multiple tries coming through so this is our response service this is our request service and if i just trigger a request over here yes we eventually get a response returned and a successful response return but we had a fit one failure request and then a subsequent success we tried that again you can see that we had an original failure request to failure retries in one successful response so we are using poly once again through the client factory but our controller code looks a lot cleaner now so that's it that was our introduction to paul it's a massive subject there's lots you can do with it this was just scratching the surface if you want to maybe see a deeper dive video put some comments in the section below other than that thank you for joining me and i'll see you again next time [Music] [Music] [Music] [Music] [Music] [Music] [Music] [Music] [Music] [Music] [Applause] [Music] [Applause] [Music] [Applause] you
Info
Channel: Les Jackson
Views: 34,395
Rating: undefined out of 5
Keywords: dotnet, playbook, .net, core, .net 6, polly, transient faults, retry, exponential backoff, httpclient, httpclientfactory
Id: DSMdUvL8N30
Channel Id: undefined
Length: 92min 41sec (5561 seconds)
Published: Mon Feb 07 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.