Context Package - Golang

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's up everyone and today we're going to talk about the context package and go now this is one of my favorite packages in go stand library it's elegant it's powerful it's well written and documented much like most of the go standard library code so here's what we're going to do in this video we'll discuss where the contexts are useful and then we'll look into the context package code and see how it has to be implemented and then we'll go over some examples and see how to use it in your code okay so what is the use of this context package say for example you have a guest over and he wants to eat pizza so you are implicitly given the task to make the pizza for them you tell your younger brother go buy some veggies and cheese and other items that we need to make the pizza so then you can actually make it that person goes to the market to get this stuff and meanwhile the guest changes its mind saying he does not want the pizza now but your brother has already gone to purchase now you need to call him and tell him to drop whatever he is buying and come back because you don't need the items anymore so context package allows this type of cancellation signals to be sent between the two programs or routines whatever another use could be setting deadlines for tasks for example you as a teenager are all too busy hanging out with your friends day and night and your parents are frustrated and then they tell you that if you decide to come home after 9 pm don't bother coming at all or if you decide to come home after two hours don't come so context package can be used in these types of situations where you need to set deadlines and timeouts another use could be sending values across the request so it's as simple as it sounds you just send values along with the context itself we'll talk about this in more detail during the demo so on the screen you can see six different types of contexts and before talking about these contexts let's look at how the context packages actually works so context package works in a graph based approach so you will have your root context which in most of the situations will be context dot background then after that whatever context you make will actually be the child of the root context so if i do context start with cancel it will actually take the parent context which is in this case context.background and it will generate a new context with context.background as the parent context similarly you can create any other context from the previous context as a parent so this sort of makes a graph it helps us because if the parent context is cancelled the cancellation is actually propagated across all its children and all the children of its children now this is very useful in complex concurrent execution scenarios okay so now that we have an idea of how the context package works uh let's see the ways in which we can create the context and go about with it so number one would be contextual background so context or background and to do are both empty context among these two context.background will be something you will be using to create the root context and then context or to do is just a placeholder which you can use whenever you don't know which context to be used so you can just pass to pass it as a placeholder next are context start with timeout with deadline cancel and value so these four contexts actually are derived context so you pass in the parent context and then it will give you the new context which will be the child of parent context so when you are dealing with some sort of cancellation signals you would use context dot with cancel this function will actually take the parent context and then return a new context and a cancel function so that cancel function we can use to send cancellation signals if you want to carry deadlines across xhr request and go routines then you would probably go with with timeout and with deadline and if you want to send some request scope values across api boundaries then you would probably use with value so a good example would be sending request ids attaching the request ids with the context we'll look into it more in our demo so now let's look at the context package so the package exposes their interface context and it has four functions in it so the number one function is the deadline func so deadline function tells us when the context will be cancelled and if there is no cancellation in the context then it will return okay equal to false the next function is the done function so done function returns channel that's closed when your program has ended execution because a context has been cancelled i'll repeat it again so whenever we send some cancellation signals either you send it or in case of timeout and deadlines the code itself sends it so whenever cancel function is being called then the channel which calls the cancellation function is sent to that done channel so you would essentially be able to catch when a particular context has been cancelled and then do anything that you want to do next is the error function so as the name suggests it just returns the error next is the value function so value function actually returns the value associated with a particular key in case you are sending values across just like you would send it with value so i'm back here on my editor and i have one main not go file ready so we'll check out one example quickly so let's start by making a root context which will be context.background so this is our root context and we'll make context dot with cancel so we'll look at how to send cancellation signals here so it just takes a parent context which will be ctx and then it returns a new context and a cancel function which we are supposed to cancel so uh we'll make a time dot after funk so i'll just say after maybe i'm sorry after two seconds run this function so this function what it does is just prints simple hello but i also start a go routine here and in this go routine i specify your time dot sleep uh just sleep for one second and after one second just cancel this context so what's happening is this piece of code will actually print after two seconds print hello after two seconds but before we give a chance for this function to print hello we actually are cancelling the context itself so let's run this program and see what happens okay we'll do go run may not go and nothing happens it does not print hello so what happened really we actually did not catch the cancelled context so if you remember we talked about a done function in context so this actually is giving us a ctx of type context right and this context interface has actually a done function assigned to it so let's catch that context cancellation now so i'll just remove this code and we'll do a select statement and in case i'll instead of using time dot after func i'll just do time dot after here and i'll say 2 into time dot second and after 2 seconds just print hello and i'll do another case here which i'll receive context.done that means the context has been cancelled so i'll just do log dot fatal if and i'll do ctx dot error dot error okay now let's see what happens here so i'll do run again and if you see it actually prints context cancel so this is the error that we printed so now we're able to catch that the context has been cancelled so this is all about propagation of the context cancellation so maybe you want maybe you run the program and as soon as you press a key then you want to exit that so that also can be achieved through the same logic here instead of just time to sleep you can provide any operation you can read the keystroke and then you can cancel the context okay so now that we have understood how with cancel works let's try to understand how width timeout and bit deadline works with timeout and width deadline are pretty similar so we'll see what is the difference when we actually jump into the code so i'll make a folder i'll just name it cancel and i'll put the main.go there i'll make another folder okay outside make another folder maybe timeout and then create a new file main.gov define the package main main as always and as always we'll again make the parent context which will be background context and will make another context with timeout which will be context comma cancel so it will return context and a cancel func and it will be context dot bit timeout it will take the parent context and it will take the time on so for now we'll set the timeout as two seconds another thing that we need to do is we have to use this cancel func to cancel it so it will allocate some memory spaces when we call this function so we it's it's always a good idea to call the cancel func and uh it will be allocate those memory spaces actually so okay now that we have done this let's simulate a timeout condition so for that i'll use the select statement again and i'll say my actual response whatever function that i'm running will take around three seconds so we'll say time time dot after three seconds so after three seconds i need to print hello come on okay but as you can see we are timing out after two seconds only so we need to catch that timeout also so for that we'll use context.done as always so we'll just do log.println we'll print context.error dot error so this will print error and now okay so i'm in this timeout directory oops what's happening and timeout okay so now i'm in this timeout directory i'll do go in main.go so what is happening here is we are timing out after two seconds but our function is actually taking three seconds to respond so if we run this i should get a timeout uh it should get timed out so yes it does the get turned out and it says context deadline exceeded that is true that is what we want so this is how you would actually want to use bit time on so when it comes to weight deadline it is same as with timeout so if you look at this with timeout function it actually calls bit deadline function internally so you are really calling with deadline always even if you call with timeout so all we would need to do is actually use bit deadline here and then instead of time dot second like after two seconds i'll just say two seconds from now so that will be time dot now dot add two seconds so it will add two seconds to the current time and this will be the deadline and if we are right then it should run the same as expected and it should time out after two seconds and it surely does so with timeout and with deadline almost the same so if we now actually do three seconds here and then print hello in two seconds then it should print hello successfully because now it's not getting timeout timed out yeah it did print hello so this is uh this is the basics of how to actually use with cancel with deadline and with timeout we'll look at with value or later when we actually look at api request because that will be easier to explain okay so now let's look at how you would send a context across api request and then how you would time out that api request or how you would send value across through context so let's make another folder here i'll make a server and let's make main.go again package main the same boilerplate and let's use uh log.panic we just panic if http dot listen answer and we'll give the address we'll say 127.001 and we'll use the port 3000 and nil okay so our http server will risk will listen on port 3000 and now let's make a handle so http dot handle func it will take part so it will be our root and then we will just call handler so we'll make a handle here oops so we'll make a handler func handle it will receive http dot response writer and and is pointed to http dot request okay let's just do fmd dot f println and we'll send hello so we'll pass w here and then we'll send hello okay handler sorry so we'll go to server and if i do go and main.go it will run the server and let's call http localhost 3000. so it should give us hello back from the server okay so now that we have the server let's make a client so we'll make a client the file would be main.go again and just use this don't want to use this again and again so i want to type it again and again so we'll just use this okay so we'll do http dot get simple get request to http calling localhost 3000 http.get actually returns a response in an error so just catch the response and if error not equal to nil we'll panic with this error for the purpose of demo we'll panic but try not to panic and just refer response.body.close we need to close the response body and we'll do io.copy so we'll copy it to so this io.copy actually takes a writer and then the reader so writer is where do we want to write this to so we'll write it to std out which is the standard output and read it from response dot body okay let's try to run this from so several i'll run go run main dot go it will start the server i'll go to client and then i'll do go and main.go it will send the http request and response will be hello okay so now we have a client server connection set up now we need to introduce the context into it so the first thing that we'll do is we'll set a timeout for this request so we'll say after one second if if it takes more than one second then time out this request so let's do that so the first thing that we need to do is make a context as always so i'll do context dot with timeout and the parent context which will be context dot background so this will be our parent context and timeout i'll set it to one second okay and we have a cancel function here and let's close this let's just defer this cancel okay and now we need to make a new request so if you want to attach a context to this request then we need to make the request so we'll use http dot new request with context so we'll pass this context and i'll do http dot method get so this is the sorry this is the method that we want and next parameter would be the url which will be http local host 3000 and last parameter will be nil which will be the body i don't want anybody so this will give us a request an error i'll check for error just like this and now that i have the request i can instead of doing this i can do http dot default client dot do request so again this will return a response an error and if error not equals to nil we'll panic and close the response body and copy it to standard output copy the response back to standard output okay let me remove this okay so now we have a context in this http request and this context has a timeout set which will be one second so if it takes more than one second then it will time out the request now we need to receive that request in our server so what do we do so we can actually find the context here so where do we find the context we have this request.context right here so i have the context here now what i'll need to do is i'll simulate sort of the same timeout approach that we simulated before so we'll start with the select statement and i'll add a case that okay time dot after so after two seconds i want this to happen okay okay after two seconds give the response back to the client with hello and if if actually the context times out and the request times out so we'll catch it through context.done as we have done before and we'll do we'll do actually log dot println and context dot error dot error and also we'll send http dot error back http dot error will take the writer and it will take the error context.error.error and http dot status we'll just send internals over here for now so now we have an handler which actually responds after two seconds and it also catches our timeout so let's run this and see what happens so we'll do run main.go in the server and in the client we'll run go and main.go and the client should actually panic because context deadline has exceeded so that's what we accept expected it actually timed out after one second because our timeout has been set to one second here and it took too long to respond from here now let's see what happens if i sleep for some arbitrary time which is less than a second surely if you understand how this works then you know it will not get turned on it will actually print hello but let's try that so i'll just do maybe 500 time dot millisecond and if i run this so server is running and if i do core and main dot go then it should actually print hello so it's successfully printed so that's how you can send your context across http requests so now let's talk about the only remaining item in the list which is context.with value so as we have discussed before context.with value you'll generally use when you want to send request code values across the http request so one example which makes sense here would be to send a request id and attach attaching it to the context so this will help keep track of our requests so this is an example which i'm going to borrow from francis campoy he has an amazing youtube channel and a very good video regarding this so i just like the example that he took and i'm going to explain you with the same example so we're going to make a sort of logger so whenever we try to print something we'll attach a request id to it so we can map the request to the log itself okay so we'll make a new so we'll make a new directory which is logger and make a new file logger.go package will be logger and we'll just use this function println so this function will take in the context which is context.context and it will take the message so we are actually mapping the log with the request id itself so request id will actually sit in our context so we'll set this later but now let's just try to print it so how we get the value from context is context dot value so we have discussed this before this context interface has a value function attached to it so we'll use that value function to get the value okay the so the key we need to put the key will be request id and this key i'll convert into type question to n64 so this value will be v and it is possible that this value is not really set at that point of time so we'll catch it with okay so if not okay we'll what happened if not okay we'll just print request id not found okay and we'll also return it since we cannot do anything here now okay so if we find it we'll just do log dot println and i'll print the request id here and i'll pin the message here so request id will be your v and the message will be the incoming message okay so now that we have this println function so what basically we need to do is every time we receive a request in handler we need to make a request id and then set the value of that request id in the context dot value so i cannot expect the user to every time the developer actually to every time call a function to set this context which is context dot with value here so this sounds like something we can achieve uh in a much better way so we'll do what we'll do is we'll make a decorator here so we'll go to logger and we'll make a decorator here will which will be decorate and it takes uh http dot handle func handler func and it will return http dot handler func it will just decorate this handler func and return it back so i'll return a function and handler func is basically it takes responsewriter and it takes pointed to the request so now i need to send the request id so this request id will be a random n63 number and now we have the request id and we have context which we get from request.context so we have discussed this before we can get it from request.context now i need to add a value context to it so what i'll do is make context dot with value and it will take the period in context and it will take the key key will be request id and the value will be your request id value which we just got okay remove this okay the context is set now all i need to do is call this function with writer and the request will be request start with context and this is the context that we are attaching to it okay does not seem happy should not use basic okay so this is just a warning for now we can actually ign our handler and in this handler it will attach this new context with value to this request okay now let's use this handler actually so in this handler instead of calling handler directory we'll do logger dot decorate so decorate this handler and whenever we want to print i can just do logger dot println it will take the context so this context will be the context and context.error.error okay let's run it again let's run the server and let's run decline now okay it's not supposed to timeout right now so we'll just change it back to two seconds so that it times out okay so let's run the server and we'll run the client as well and if you see it panicked as we expected and context deadline exceeded but here you can see that it printed request id and it says context cancelled so that is actually uh what we wanted some formatting issue is there i think ah okay that's my bad so let me run this again just to print the output property and what the hell oh okay so this is actually an integer in 64. so let's clear this okay so now it printed properly so this is our request id and it says context cancel so basically what we have done is you attached a value to this context and then received the value with dot value here so this is all there is to uh to the context package so we have covered all the four things all the six things actually so our background are to do and with timeout with deadline and with cancel and now with value so this is all i have for you today so if you like this video then please hit the like button and maybe subscribe to my channel and we'll come up with more interesting videos moving forward thank you
Info
Channel: Akshay Gupta
Views: 1,805
Rating: undefined out of 5
Keywords: go, golang, context, code, programming, development, go developer, golang development, go standard library, go standard lib, context package, context in go, context package in go, context golang, golang context, go context package, go context, background context, TODO context, todo context, context timeout, context cancellation, context value, context values, cancellation signals
Id: 9XH-ziX2Y68
Channel Id: undefined
Length: 29min 33sec (1773 seconds)
Published: Mon Feb 01 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.