justforfunc #9: The Context Package

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Thanks /u/campoy for this helpful tutorial! It's actually very timely since I'm at the point now of building an HTTP server where I would like to clean up all the resources when a request is cancelled.

I learned how contexts are used in general because it can be very confusing to think in concurrency when using Go, which you were able to clarify. You explained how the "tree" structure of contexts, which was the trick to understanding it. Previously, I was very confused with the point of a background was but it's in fact very simple.

But the most important and useful trick was how to use the select statement to immediately to free up resources across goroutines, very helpful!

I hope you continue to create more videos like these. I like to believe your motivation for choosing such a topic is that you have a good feel of what people are struggling with when it's pretty simple, and even very powerful - such as the impression of the context package. Thanks!

👍︎︎ 2 👤︎︎ u/eldosoa 📅︎︎ Apr 03 2017 🗫︎ replies

Thanks! I enjoyed it and learned something.

👍︎︎ 1 👤︎︎ u/DrKeto 📅︎︎ Apr 01 2017 🗫︎ replies

Thank you! Very informative and enjoyable as always!

👍︎︎ 1 👤︎︎ u/AUTOMAGIC 📅︎︎ Apr 01 2017 🗫︎ replies
Captions
hi I am Franciscan boy and this is just for fun so hello and welcome to episode number 9 of just for fun today we're going to be talking about context we're going to be covering what is the context value exactly how to create values to pass them to functions that require them how to define functions that receive those context values and then also how context can make your HTTP clients and servers more efficient and less wasteful so let's get started with a theory so even though the context package was only added to the ghost' on a library with go 1.7 the package itself existed way before before being in the standard library was undergone under org slash X slash net slash context and even before that there was an internal implementation with a very similar API that we used at Google the implementation itself has changed completely but the API is actually incredibly similar some tiny little things that have changed is a very simple package it has around 500 lines of code so really not that many and I encourage you to go and read the package maybe I might do an episode on this on the inside of the context package but today we're going to be learning about how to use it and why to use it why you should use it there's a main usage that is important for us which is cancellation and cancellation propagation so what does that even mean so cancellation is when you are requesting some service you can say actually never mind right so let's get an example imagine that you asked me to go make you a sandwich right and for me to make a sandwich for you it will take me a bunch of steps yeah we'll need to go buy some bread then buy some Tomatoes buy some whatever ham or whatever and then put everything together then pack it and give it to you right like there's a bunch of steps if at some point you are like hey you know what I actually don't want son don't want that sandwich anymore I should be able to stop everything that I was doing right even if I already started and I'm on my way to buy tomatoes I should be able to stop it that's what we call cancellation and cancellation propagation means that if I actually ask someone else to go buy those tomatoes I should be able to say to that other person hey actually I don't need those tomatoes anymore because I do not need to make sandwich right so you have cancellation and propagation two different things that are very very related bring it then on the other side there's one more thing that context blue which is to send values and those values are very useful especially for like if you want to log stuff and we will talk a little bit about how to use them at the end of the video but we're going to concentrate mainly on the on the cancellation and propagation side of the complex cool okay so let's get started with a little bit more of code okay so if we go to the documentation in the standard library for the package context you will see that there's actually two types data exported one it's just exported for documentation purposes it's canceled funk and we'll see what it does later on but you should not care about it that much the important one is the context type so there's a context type in the context package there is an interface and it has four methods so there's three methods that are related to cancellation and propagation and one method that is related to values and value propagation okay so this means that we have a function that we choose the context we need to send a context value but if we have an interface how do we care how do we create new values this is actually a bunch of functions that are specifically designed for that the first one is context our background and background is when you have a context that you don't you're not reacting to anything you're not reacting to anything else you just starting the action right and on top of that you don't need any cancellation or timeout or values you just create the route context right there's actually one route context which is background the rest is just children created from that would come and and it's important to talk to hear that route and children because actually what we're creating in a tree of context if I say please make a sandwich and then you say to someone else please go buy tomatoes that is actually creating kind of a tree of dependencies or a tree of request that we're sending right context will follow the same structure of tree okay so let's start to use that context of background to define it which simply call context dot background and there you go now we have a context of background I have this one a function called sleep on talk and if we read the documentation for that and you will see that sleeper talk gets three parameters a context a time that he should sleep and then a message that will print after sleeping for that time right so we could say we're going to pass a complex and we'll be fine it in a second and after five seconds you should print hello now that context we're going to use context the background as we said before if I'm able to tap it there you go so context of background will never be canceled which means that if we run this whoops that is drag go go wrong you should see after five seconds it prints hello cool now what else we could do what we might want to cancel this eventually right okay so let's say that for instance we want to cancel as soon as we are able to read something from from inform summer input so we could say we're going to create a new context that is a child of the previous context though its context of background but now we're going to add cancellation to it so we're going to call context with cancel of context and we're going to pass that context that provides consolation to this we're going to read from standard input we're going to create a new reader a new scanner why not a new scanner and we're gonna scan okay so cancel has never used okay so as soon as we're able to read anything we should cancel okay so now what we have here is if we don't do anything after five seconds we should print hello and finish there you go but if for any reason we type something we cancelled that context so we're able to stop the sleet on top function to just stop it directly by canceling the context which is pretty cool right so you can do these things where you have a cancellation and you're the one managing one to cancel that given contact now imagine that instead of doing this you wanted to cancel it after sleeping for five seconds so you could do something like this right like you could do time sleep time dot second so usually for a second then you cancel it this is pretty similar to simple code the nights wait for a second and then cancels it seems sleep on top is waiting for five seconds we will cancel the context every time before anything gets printed we could write this in a better way simply saying time after funk and time after funk will do exactly that so it will say after one second please call cancel this is exactly same code right so again if we run it we'll get the same result now the cool thing is that you could simply say what I'm going to do is I'm going to do context with timeout and then not get the context and also the duration so now we also get very similar code as before but now we can trouble of this an important thing we actually need to call that cancel regardless of if we care about it or not so we clean though is deferred calling that cancel function at the end this is important because the count package will allocate some resources for timers and when you call Council those timers will be released so it's important to do it so we've seen the three ways of creating context context of background with council or waste Anna you could also use with deadlines and with them and you could say actually I want it to stop today at 5 p.m. it's pretty much the same area it's basically power ways of setting tables okay so how do we use that context inside of our function so let's try to define that same function here so we're going to call it my sleep on top so the partner is our I contest our context duration and string so what we can say is I want to sleep for 3 and then print message right and I'm going to call my my sleep and talk so if we do this even though we cancel in the context nothing happens and we feel wait for 5 seconds of you we call hello we print hello why is this well because we didn't do anything right like we we get a context but we're doing it so what we need to do is we need to verify that context for any reason what cancel right we want to do that at the same time that we want to sleep so either we wait until we've done we're done flipping or the context is closed how do we do it well luckily for us the time package allows you to rather than do sleep to get a channel that will receive a value only after a given duration so all of the time we have two different channel operations that we want to do exactly the same time and for that we can just select so we're going to change this time to sleep for time but after and you can see that if we turn that channel of time and we're going to do select so if we're able to read from that then we print right these exactly same colors before so far we haven't changed anything so if you run this we should be able to see that after five seconds it prints hello we changed a little bit were cut but we still not take into account the context but now it is actually very simple we can say if context of done we can read something we're going to log context of error and now all of a sudden after one second we print content Dana content that context deadline activity if we were actually calling cancel directly we get instead get a context cancel those are the two errors that we mentioned at the beginning cool so now we're able to see how to receive how to send value how to send context values and how to receive them and handling correctly thoroughly you could also do pretty much the same thing and pass those contexts around and create new ones but I think the masking the most interesting part here is the fact that you can create new deadlines and timeouts and cancellations at any single step and just pass those around if for any reason the contacts on top gets cancelled that cancellation will propagate to all the children contacts and all of those operations will stop great and that works very well here on my laptop running code that only runs in a single process right what happens if you're doing communication over the network what happens if you're doing HTTP well let's see that because this is actually the coolest part of all so I'm going to create two directories I'm going to create server and I'm going to create client right here and my client so let's start with a server we're going to create I'm in the go and that's going to be your day to day HTTP server so handle func everything with Handler and then log fatal of HTTP and serve of one 27001 a 80 and male and then we need to define an HTTP handler can I call it Handler and this is going to seem to say s println yes println hello cool and the fine HB hand handle is a composer handle funky there you go like that cool so we have a very simple actually let's log some something here handler studded and beefer handler ended okay so we discard what we're doing is whenever we receive a request we just print hello back to it but also we're going to be able to bring handler started in handler and it once we've done let's make this very very slow so we can actually see how this works so we're going to simply add title click standard flip five seconds okay so let's write first I'm going to run that server and now it's running anybody curl localhost 8080 should wait for 5 seconds and then print hello and here we should be able to see handler started handle ended after 5 seconds so you're able to see everything everything is working cool so now let's write a client that calls the server so I'm going to go back here and I'm going to create a new file whoops not any folder binding file main let's go package main source main and HCP get localhost let's go host 8080 nothing again localhost HTTP localhost AAA okay cool and that will get response on an error if there is o'neil if there is nothing no we should log fatal error otherwise we going to check if the status actually let me out of it if status code is not HTV status okay we should lock fatal the status and we're getting panics I'll fix that in a second okay status code and all the wires we will copy to the stand of output the body of the response and remember to close the body of the response cool so we have now the client let's try so we go to client these fronts it doesn't work because our server is not running so let's relate to on the server and now the client runs with for five seconds it should print after five seconds hello great okay so let's now add some contact handling on the server so what context right like should we use background here there's no context there's actually a context which is hidden here in inside of the request so that is our context and now instead of sleeping for that time we're going to do something very similar right we're going to do our selects going to be here we're going to use standard after so that's going to be where ke ke is reading from there just print hello case receiving from context that's done we can do let's simply call so that we're going to log something log printf context dot error but also we're going to return HTTP error of the error and let's say internal server error which is not really the case but we should be okay um Oh print it should be error not happy - that is context that are dot error no very happy with that let me ride that okay cool so now the server what it's going to do is if we cancel it we'll be able to say you know you need to stop and it will return and demo status internal server error page rather than going through the whole operation which is cool right but there's actually something even cooler which is when we run the server now so if we send a request set on the side wait for five seconds and it exits what is cool is that if we cancel it here so we cancel the curl we drop that concern that we drop that connection the server will also receive a context cancellation and that is awesome because what it means is that all of your HTTP servers now they're able to stop their to stop processing the tasks that they were asked to do if they know that the time will never receive it so all of a sudden imagine that if you were doing something actually expensive not just thanked don't sleep but you were doing something like calling some server or going through a bunch of data files or through a database you do not need to do this if the client will not receive it and now you have a very clear indication of that with context which is awesome great so we have that but how do we use that from the client in our client what we can do is as we were doing before we can create a context and where do we put it right like there's no place for context here so what we need to do is we need to separate these this HTTP GET into two steps we need to first create the request and then send the request so we're going to create a new request with method get the URL is going to be the same one as before and nobody that's going to be our request and that could fail if it fails we're just going to log fail all that if you fail this because either the method is not doesn't exist or the URL is not really URL so that should never happen in this case okay so now these will do htpb for clients do of the request and request dot with context will allow you to create a new request that has a request in there let me say that again Greg with context will create a new request that has a contact inside so you could be wondering here why isn't there context filled in the request struck and actually the main reason is because if you added that then we could break the 1.0 compatibility right because imagine that you're creating a for some reason you're creating a request and all of a sudden you add one more method and your code might break because you're if you define any request without using tags which you should not but you might if you did that then all sound is one more skill to declare which means that everything break sad but that's how it is so instead that's what we have with context to set the context and context to be to retrieve it it's kinda like yet unset really ok so we do with context of the context we'll get a new request and now recently so now this code doesn't do anything extra anything new right so if we run it we're go to the client go run indigo this will still wait for 5 seconds and then finish it but and then green hello but we can now very simply add context cancel come sticks with timeout come to expanded second differ cancel right as we did before and now if we run this we will see that after one second we already returned here content deadline exceeded and our server also said the context has been cancelled right which is pretty nice so now let's done you get all of these power of being able to cancel operation as soon as they're not needed anymore and this implies adding some extra from China here and it means that very often you're going to need to add channels so you're going to be able to do that select statement but in exchange you're actually getting way less resource wasting because now you're able to notice that all the work that you're doing is completely pointless so there's no point of bringing them sandwich if they will not be there anymore ok so we talked so far about cancellation and propagation of that cancellation also known as cascading basically if I cancel whoever was using the same context where there was will also be canceled cool so what about values well the first thing to understand about values is that they're probably not a great idea to be used and if you're considering using values before doing it think about if it's really something that it is what we call request scoped meaning that if it's something that it is not only related to that request so for instance let's say it's some option on the server or even a database connection should not be in the context that should be in a server type or some flags maybe even a global variable than not in the context and if it's something that is related to the specific request but it is something that it is important enough like let's say it is something that you're going to act on it should be a parameter it should not be in the context why because in the context everything you put in there is completely invisible right so very easily if you start putting too much stuff in there you will get to a point where it's actually hard to follow what your code is doing so the two rules basically as they are one whatever is in the context should be request specific and two whatever is in the context should be information that add information it's extra info that is useful but that's not impact the flow of your program so knowing things what could we use as an example a very good example for this could be for instance requesting you like if you're logging all the things that your program does you might want to have a request ID to identify in a single server all the things that are related to one single request can you do that well actually it's pretty simple and that's we're going to be doing now so I'm going to start by creating a new package I'm going to call it let's call it log and instead of log we're going to have our main des hommes log go okay so in that package we're going to have is we're going to define a println function that on top of receiving the methods to print is also going to receive a context right so message string and what we're going to do is we're going to get a value from that context that we're going to be that we're going to use to identify what we're printing right so we're going to do let me say that so context value and we need to get a request ID key that request ID key we can say can't request ID key is 42 let's say it's 42 whatever any number could work right and that will return and at the interface so what is that into and what is that empty interface well it could be meal if we were the unfunded or it should be whatever we put in there so let's say that it is also an integer is I mean 64 for some long request right so we could do in 64 and then say that that is the ID but then it means that if for any reason the value in there is not good or if the value is not there so if the value is not there or if the wrong type this will panic so we can add okay so if not okay then we could actually print something saying print the land could not find request ID in context okay and return it doesn't print anything that doesn't know what to print we could do that and otherwise it trains the value and the message so ID and message go so this is the part where we retrieving the value but we still need to put it in there so when do we put it in there so we could have a function that given a context we add a new context but this is actually something that people might forget to call so instead what we can do is we can create what we call an HCP decorator basically it's just a wrapper of an HTTP handler funk so I'm going to call it decorate and give them an HTTP handler punch it will return an HCP handler point okay so what we want to do there we want to with return and HTTP handler funk and this HCG hunger funk I'm going to say it so much that the first thing it does is it generates a random number actually the first thing it does it gets the context from the request so context and the next step is going to use run dot in n 1963 to generate a new number that's going to be our ID that we turn down in 64 so it's going to be some random number and next step is going to put put it in the context so it's going to do context with value of the previous context and then our key and then the ID and now we want to use that new context instead of a request to call the previous handle funk so we're going to call F with the same response writer but we request with context context so now we are receiving a context adding a value and sending it back okay so how are we going to use this from server now so we go here the first thing is we're going to drop the log here and we're going to be using my amazing blog just for fun comes to oh it was there just refined context log that has logged or decorate so we can decorate a handler and it returns on the handler so this still works our print will now require context context and context oh and this needs to be string so we don't need to call air okay so now we didn't do anything we didn't do much reading right but all of a sudden without knowing our code the handler code doesn't know about that cheat at all but it is not important because when we run our code go around main logo and we do a curl on localhost 8080 we can see that that request there it is a new request that was generated randomly and every new request will have a different request ID which is very nice okay so now this works but there's a little bit of an issue which is it could be quite easy that someone else in the world decides to use the same key as I did the integer 42 and then we could have collisions so for instance we can fake that by saying context with value of context and we're going to use the same in 42 years before but now we're going to use I need 64 there is going to be 100 right and now if we run our server so go around mailer go and we send a request you will see that we get 100 all the time which is not what we want but at the same time how the Fishkill know that it was entered in like I mean with the value 42 that was our key right the chances of having a collision are pretty big but we can avoid this very easily simply by making this value of a type that we do not export so now I'm going to say type key is an INT and the requested e keys of site key now this T is a site that only the log package can use so if we rerun our program here the farm is gone and even better there's absolutely no way that this code could clash with what the log packets doing which is exactly what you're looking for so there's actually a pretty nice side effect of two different values of different types being always different when you compare them as at interfaces it is a side effect that sometimes it will be surprising but in this case makes it for a very nice experience okay so this is pretty nice and it shows you how you can send values across functions that do not really know about them and they don't really care but what about when you want to send them from one server to another will be just work we can try it we can say our main dog go we're going to add our client we're going to add value so we're going to do contact with value and let's say that we're going to attach to the key food value bar and then from here we can try from the former client we can try to get that value by saying context that value of foo and which is going to print it to the output printf value for foo is that thing so now if this works we should be able to run our server run our client and see here that the value for food is male so this does not work but there's a good reason of this which is if you actually want those all of those values to descend across servers you will need to write that code it's actually not that hard and you could definitely encode these and send vanilla and the header probably requested it could be a great header to send but you will need to add that code the HTTP package will not do it unlike with cancellation where it will actually go over different servers because the TCP connection drops and that is the information we're using for all the things like values we do not propagate so it's important to take that into account great so this is the end of this episode I think that we cover the basics of the context package now I hope that you all know what the code what the context package does why would you use it how to use it and what are the limitations I hope that you enjoyed this episode let me know if there's anything else that you might want to learn about the context package I will be working on the next episode that will come out in 15 days as always and by then I will be in China for graphic on China so if you're in Shanghai please let me know and I'm thinking that that episode will be again code review so send me your packages send me if you have a repo that is simple enough but not too simple that you think might be a good thing to read and to evaluate doing around 30 minutes sending my way you can send it through Twitter and on Twitter ask on task or you can just simply put a comment down here and now that we talk about things around here click Subscribe I keep on having more and more followers which is awesome I love your comments I love your feedback so please keep it coming so as always thanks for watching and see you all in to it [Music]
Info
Channel: justforfunc: Programming in Go
Views: 129,654
Rating: undefined out of 5
Keywords: golang, justforfunc, context, tutorial, programming, coding
Id: LSzR0VEraWw
Channel Id: undefined
Length: 36min 27sec (2187 seconds)
Published: Fri Mar 31 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.