Building Microservices with Go: 2. Introduction to microservices, continued

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello well welcome back episode 2 I am pretty excited I'm really enjoying this series even though it's only the second episode but there's just so much good stuff to come alright so last time when when we were kind of looking at some stuff what we were doing was looking at a very simple example of how to build a service and go and the the kind of the you know the the kind of the code sort of perspective on that well it looked well somewhat like this it was about as basic as you can get and and in fact this is probably well you know don't think you could write less code to create a web server and go but what we're gonna do in this session is we're we're gonna take this and we're gonna start a refactor it a little bit I want to kind of start bringing in some some better patterns and some better practices for for structuring your code because these are gonna be really important as we we go along with the series so the first thing is we've got to start looking at these these handlers so we've got HTTP handle func there and it's it's kind of all a bit untidy we're ending it with a lot of code inside of our func main we're gonna have to think about testing at some point and in a few weeks we'll absolutely be running through that so how would you test this code other than manually and then you think when we add the complexity into there how are we gonna test this code so we need to start refactoring it so what what's gonna be the first step what's the first thing that we we want to do well I think the first thing that we want to do is get all of this this all of the content of this handled func into an independent object so how let's see how we can do that all right so what I like to do is I like to add a package from I my handlers so a packaging go I'm just going to create a folder I'm calling it handlers and then inside of that package what I'm going to do is add a new file and let's add a a hello dot go okay so it's a blank file package handlers so the standard kind of start over of a go go file so what we're going to do is we're gonna create a strut so if you remember back from what we were talking about last week what we were saying was that this htb handle what it actually does under the hood is convert the function that you're passing as a parameter into an HTTP handler and it's registering it with the server so an HTTP handler if I can bind it in the documentation is an interface and it's an interface which has a single method on it serve HTTP of response writer and request so that's exactly the same signature as this so in order for us to create handler all we need to do is create a strut which implements the interface HTTP handler so let's do that okay so first things first let's create that strut so we're gonna say type we're gonna call it hello we don't need to call it hello handler or anything like that because we're already stating that it's in the package handler so type hello type struct and I've typed that wrong and we'll just leave it blank for the time being so we add that interface so let's add the interface which sorry the the method which satisfies the HTTP handler interface so defining a method on a struttin go so we're gonna do func we're doing the name of the type which is hello serve HTTP which is the signature first parameter is going to be a HTTP dot response writer and I'm gonna call that RW and I'm gonna call my second parameter which is a reference to an HTTP dot request no return parameters so that signature there is is what what we need to to satisfy the HTTP handler interface so I can copy my code in right so let's just go ahead and completely copy all of this into here now we can look at a couple of things here so the first thing is that that I'm using a logger here now but that in itself is is fine but actually I I'm gonna want some control over this logging at some point if I'm using maybe a database in here I'm gonna need to to have that as an object I don't really want to be to be kind of directly creating concrete objects inside of the handler if if possible to avoid it and the reason for that is again when we start looking at testability we're gonna need to be able to replace those things and use some techniques called dependency injection so don't don't worry too much about that right now what we'll come back to that but what I want to do is kind of define that pattern that we're gonna use and I want to show you you know how how flexible things are if you are familiar with things like dependency injection specifically and go so what I can do is I can define on my handler a field so I'm gonna add arms can call it log and it is that's probably a terrible name ones call it L and it's of type log dot logger and then what I will do is I will follow a sort of the idiomatic prints of creating go code and I'm going to define a function called new hello a new Hello is going to take a log dot logger and it's going to return hello handler as a reference so I can just quickly fill in those details there we only got a single parameter so we can just kind of cheat you get that there like I'm okay so let me just tidy up these references these import references here I will not get on to the rant about how broken tooling in go is right now since goal mod has come in I mean I promise you I won't it doesn't irritate me in the slightest and I'm just gonna redo those set up those imports alright so I've got my new hello handler then I've got my my serve HTTP handler so my my serve HTTP handler there is there's literally nothing different from from what there was before I've just extracted this out into its own strut now the benefit of doing that dependency injection there so that new hello which takes the logo in my test I can replace logger with something else I don't have to worry about the concrete implementation and for logging like all right I think it's pretty useful sometimes you want to log to a file sometimes to stand it out or something so it's nice to configure that on a broader level but when we start getting into connecting to databases and connecting to other services and things like that we really really need to be doing dependency injection to be able to write good fast unit tests so I'm going to replace that log dot print line with just H dot L because L is logged logger and loved a logger has a print line method and then exactly the same way format dot printf you remember that RW sorry the response writer implements IO dot writer so wherever I can use the IO writer in the face I can also use my response writer so format the printf takes an IO writer as a first parameter and then I can do just my standard kind of format string there which will write out to serve HTTP so let's just let's just get this up and running because I kind of will ignore the second handler for now so we need to create a reference to the handler okay so we're gonna do I'm call it hello handler and it is handlers dot new hello and that needs a logger so my logger is going to be log dot new I'm gonna I'm specifying my logger and I or writer so I mentioned earlier it's sometimes he's pulled a log to a file I'm just gonna log 2os not standard out so a start standard out my prefix this is a nice a nice feature of the logger so my service here is is actually a product API service or you will see in the coming weeks that it will be product API is gonna be my prefix and my flag it's going to be logged art I think we've got standard flags or something there we go we'll just do the standard flags I can then inject that with handlers dot new hello so now what I need to do is I need your register that handler with my server so how am I going to do that so when I used the the function h TV p dot handle func what is actually happening under the hood there is that we are registering the where we're converting that function into a half the type and we are then registering it onto a thing called the default serve marks so the default serve marks is a server multiplex multiplexer so it allows you to have multiple handlers and it contains logic to be able to determine which one call based on the the path let's take a quick a quick look at that in the in the documentation because I think it's worth it's worth looking at there we go surf marks so serve marks is an object and it has methods like handle where you can define that a particular pattern is is kind of directed to a particular handler and again handle func so the the kind of the package level function I was using is also a function of the the surf merckx object not so much type type object oh somebody can correct me in the chat I'm sure and then some we've got this handler method and handler allows you serve marks to return a handler based on an HTTP request so internally what is happening is that when a request comes into your server the server has a default handler now that default handler is actually the HTTP server marks so the the servo is gonna call HTTP server marks dot served HTTP server marks is also a handler okay I hope I'm not lost anybody yet but the special logic inside that serve ma as serve HTTP in the the HTTP server marks and it determines which of the handlers that are registered against it to call it then in turn will just call the serve HTTP function of the handler based on what if the request is and pass through the response writer and the request it might be easier if we just look at the code and dig through that so let's just create it so what we want to do is we want to create ourselves a new serve marks so it is HTTP dot new serve marks okay then on the serve marks were going to handle registrar handling so I want just any fare any path I'm going to register and I'm going to register that to my my hello handler now if you remember when we kind of looked at the basic session last week again one of the things that we had was that we said that listen and serve takes two parameters the first parameter is the the bind address so here I'm binding to everything every IP address port 1990 and the second one is the HTTP handler now if you don't specify the HTTP handler the the server is actually going to use the the default serve marks I don't want that I'm gonna specify my own serve MUX that I created because remember serve MUX also implements the handler interface so let's just see that working and then we'll dig in so we can just do go run main doc oh and we've got some things to clean up okay I did mention you know the tooling is kind of broken at the moment isn't it alright that's running there let me just grab a new terminal and I can curl at endpoint so curl localhost 1990 I'm gonna just pass some data and I'm just gonna say Nick and it comes back with hello Nick so everything's working as it was last time but we've done that little refactor and we've cleaned up our main logic here and we've moved everything out into our into our handler like so and that's really nice and very very quickly what we can actually do is we can add that goodbyes handler in there as well so very quick let's just add good bye dot girl package and lers type good bye struct it's gonna have a logger on their log blogger we are going to create that no new function so func new goodbye pass it a logger and we're going to return a goodbye handler so yeah right and then again we we create a handler a handler has to have a serve HTTP method to to sort of adhere to the interface so it's funk and then it's going to be G for goodbye to add the method serve HTTP against response writer hooked response writers an interface which is why I'm not using the star there request is not request as a strut so you find that there that's why it did its reference with the star and quite simply here what we're gonna do is we're just gonna write to the output so I was using format dot printf I can also do things like just write a straight forward you know bite to that so by like that and then again back over here what I can do is I can create the new instance of my handler so I create my goodbye handler handlers dot goodbye pass it in my logger and then I'm gonna register that with an endpoint goodbye and like goodbye handler so that's that cleaned a barcode quite quite substantially I think and we can test this so let's just quit that and we will obviously fix my PAP kak because if there's nothing I am more proficient at it is making typing mistakes and tidy that up as well if anybody is working with going you're very new to it you you probably find that the kind of the tooling is oh it works pretty good most of the time but I think that the kind of there's been a very positive shift towards go modules which which is it's necessary but in the kind of the interim some of the tooling that we've used for a long time such as being able to do automatic imports and some great stuff that like Fatih is written from who created them go some great stuff for the visual studio code or I am working on and sort of go some wonderful tools for kind of doing intellisense type stuff well that's kind of coming under the under the fold and you'll you'll kind of start to see that improving over the over the time we've now got to go language server called go please and it's it's getting there but yeah can be can be a bit frustrating sometimes I'm not gonna lie all right let me just run that again just to prove to you this is all working good bye and then we're running bye okay so we've we've registered those two handlers now so that's that's actually cleaned up cleaned up our code quite quite substantially but we're not quite at the pattern that we we want to be at yet and the reason for that is that we've got to start thinking about defaults for or things like timeouts so why is the timeout important well the timeouts important because think about this resources are finite there's only so many connections that your server can connect and connect can handle at any one time so if a client connects to the server and starts do something and energist pauses then that's a blocked connection so when you get multiples of those blocked connections ultimately the server then can fail to to satisfy the requests and and it's a kind of every basic denial of service attack so really good practice when you're building a service is you you kind of just tune those parameters a little bit so the HTTP listening service is gonna give us a good sort of basic but what we actually want to do is we we want to kind of dig in a little bit deeper and start looking at the the tuning of those elements and we can do that by manually creating a server and I do that by creating a an HTTP server like so so an HTTP server is is just just a type in Ingo so once I've got my my server the server has has various properties on it so let's let's take a look at that quickly in the the documentation go documentation and golang.org I think is it's really really nice go documentation is I've always been very impressed with what the team do with with that and also the community I like the kind of the precedents that get set but very very nice so the server it's got some property airfields we've got the address we can set our handler we can set up some TLS configuration what we're going to look at TLS a little bit later in this series but so we'll ignore that for now but we have things like the read time out the maximum amount of time that a server will read from a client so if a client is uploading a large file it needs to a relatively big read time out if it's not sending anything really at all it can have quite small one so we can put an element of protection in there and again the right time out if I'm not writing a great deal of information a slight tiny little blob of JSON then I can create quite a small write time out if I'm sending a huge file at gigabits in size then I potentially want to create a large write time out so I'm gonna tune these parameters based on the function of my my service and you're probably looking and going well what if I've got one handler which only sends a tiny little blob of JSON and I've got another handler which sends great big files do I have to have one sort of timeout to to rule them all and the answer is we will come to that in the next session and we'll look at how you can performance tune that because it it it's possible it's just not as straightforward then we have things like the the idle timeout so the idle timeout is all around connection pooling so that there's a kind of TCP connection keeper lives because when a connection is made to your server making that connection establishing it doing the kind of the DNS lookup and the handshakes and things like that is it's not free it costs time so if you have a lot of requests from a single client you can make it more efficient by keeping the connection open so the the client will use the same connection to the server over and over and over again this is particularly useful for things like when you've got lots of micro services connecting to to each other now I I kind of want to maintain persistent connections between those because I want it to be as I say to be performant especially more important when I'm using TLS which is a little bit more expensive to establish a connection than just pure pure TCP but we're going to kind of tune this as well if you're making requests if they're coming from just random clients all of the time and users then you know potentially you you would kind of run a low idle time out I mean I think genuinely probably wouldn't find that you're getting and connection keeper lives use that often but again when you're running service to service you probably want a higher idle time oh you want to keep those connections alive so let's just put those details into to our service so got our server so first things first we are going to set the address and we're going to set the address to exactly what we're doing before I want all IP addresses on port 1990 I'm going to specify the the handler and the handler is going to be my serve marks I'm going to set the idle time out and I'm just gonna set that to well I don't know 120 seconds it my service doesn't really do anything at the moment I'll tune that later 120 second and then what I want to do is I want to set my read time out so my read time out I've got a tiny tiny tiny little bit of information here so I'm gonna set this to just one second and then I've got my right to timeout and again yeah this is really sort of low piece of information so I'm gonna set this as we kind of run through the the kind of the information that I want to teach you in this there's this series of videos I will look at how you can actually tune these things properly we're going to look at that when we get into things like observability but again for now I want to set a pattern that we can use time and time again so then to to run that what I'm going to do is I'm just going to do server dot listen and serve and that will run there okay so let's just again quickly just check that that will run and we're all good right so what's next we're nearly done with this basic pattern the only thing that I want to look at next is graceful shutdown so graceful shutdowns actually really important because if you're sort of doing something like if I've got a large file upload hour if I'm doing a database transaction or or something like that and then I just decided that I'm gonna shut the server down because I want to upgrade the version of it or something like that if I don't do it gracefully then I'm running the risk that I'm just disconnecting my client they're not allowed to finish the work that they're doing and it's gonna throw an error at them where is with the the ghost server what I can do is I can use this shutdown function oops and what shutdown does is it it will wait until the requests that are currently handled by the server have completed it'll then shut down so the immediate when I immediately call shut down the server will no longer accept any more requests but then it's gonna wait until everybody's finished their work it'll finish the program will exit and then we can do our upgrade or whatever without any interruption again the kind of the concept on why this is important may not be a hundred percent obvious to you right now I think when we start looking at things like reliability patterns and we start looking at some of the techniques around canary deployments and things like that but we're just gonna kind create a nice base pattern that we can use so what are the parameters have shutdown so shutdown takes a context so what I can do is I can create a context so I'll call it a timeout context context and it's going to be context with with deadlines bass is going to just be contact start background and the duration I'm gonna say I'm gonna say 30 seconds so I want you to allow 30 seconds to attempt to gracefully shut down all of the work that's happening if none of the handlers if sorry if the handlers are still working after those 30 seconds forcefully close it so then I can specify shutdown down there with with TC so I'm gonna call shut down with my context my my deadline contacts okay so this is obviously going to block here Ingold serve so we need to we need to refactor a little so we're gonna put this into a go func and we are going to call shutdown we're gonna get the error from that cuz we're gonna be good citizens and we're gonna see if error is not equal to nil then what we want to do is log dot fatal with that error message but ultimately that ServiceNow will will will start and it's not going to block because I've wrapped it up in a in a go function but that means that also it's going to immediately start a shutdown so what we can do is we can use the OS signal package and in the OS signal package we can register for the notification of certain certain signals so we can do OS dot notify bear with me let's run up to the docks over here we are going to do OS and we're going to find notify OS dot it's actually OS dot signal and here we see you've got notify so notify takes a channel and a signal so let's see how how how that works os don't notify and then we're going to specify that Channel and the the signal so just quickly looking at that the channel is of type OS dot signal so let's create a channel so I'm going to create my channel which I'm going to receive my signal and call it cig Chan and it's going to be type Chan OS dot signal so then I can call OS don't notify SiC Chan and I'm going to say I want signal dot interrupt so whenever a signal dot and an interrupt signal is received by the system it's going to send a message on that channel so I'm gonna do signal and I'm also going to register for kill so I'm gonna do OS store kill so I'm gonna trap a forceful kill and also something like control C okay so I register those there and then obviously what I do is I I do need to block so I can just say I don't know like sig is sig jam and then down here I can just do a log messaging say log dot L dot print line received terminate graceful graze full shut down or something along those lines and let me just throw the signal into there so this is now gonna block so we're pretty much done here we've just got to do those imports that's actually signal done notify not oh ass Nick oh I moved my stream to my camera oh good lord I pushed the wrong button didn't I how long ago did I do that I do apologize so just backtracking looking at the the code here I'm handling my my listen and serve in a go funk so it's not gonna block and I have my cig can which is going to be single notify so signal notify is going to broadcast a message on this channel whenever an operating system kill command or an operating system interests or interrupts is is received there we're obviously going to block here because reading from a channel will block until there's a message available to be consumed and then once I have consumed my message then what I do is I'm just going to shut everything down so we can we can run that and OS I'm just going to manually do the job of my tooling and I'm going to tidy up my typing mistakes because there we go and I think that's the last typing mistake no 45 okay context is deadline returns a function as well I'm not interested in that so I'm just going to ignore it cannot use okay what have we got a D time dot oh sorry with time up context of deadline would have been an absolute time I want to just use a timeout so 30 seconds elapsed my title right okay so that's now now running we can kind of see here that if I curl I've got my hello Nick I can do my good-bye and we see the bye message there but now when I do control see what happens is you see I'm getting that received terminate graceful shutdown and then it's telling me the signal type which is interrupt so that's gracefully allowed my my application to to close any work that's going on in the handler which in this example is known but will close gracefully so any database connections I might have open I can close them any large uploads that I'm doing I can finish them or any communications to another service I can do that gracefully I didn't do that without interruption or I returned any of my clients and and we've defined quite a nice little pattern there very very simple again but we're starting to get into a shape where we've we've really kind of got something that we can start putting into production like all we needs now is really some unit tests around our handlers and we're we're doing pretty nicely and that's what we're gonna start to look at in a little bit but next time what I want to look at is how we can kind of start implementing more restful interfaces so how do I control through HTTP verbs get post etc how do I start being able to pass a parameter as part of my my URI and to to be able to read that and we're gonna look at that will first look at how we can do that with the go standard library and then we'll start to look at some frameworks I'm big fan of the guerrilla framework so we'll look at guerrilla framework and see how that makes our lives easier and that's coming up this this weekend thank you so much for for watching I apologize about the sort of the I press the wrong button there and we change the camera if that was really bad when I review the video I will upload a new video of this again so you can watch on on the review but thanks so much for watching like and subscribe and I will see you next time catch us later
Info
Channel: Nic Jackson
Views: 43,228
Rating: undefined out of 5
Keywords: go, microservices
Id: hodOppKJm5Y
Channel Id: undefined
Length: 37min 22sec (2242 seconds)
Published: Wed Jan 15 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.