Keep Those WebSocket Connections Alive!

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
ladies and gentlemen there are a lot of different reasons why you'd want to use websockets in your application but no matter what your implementation is there's nothing worse than dead connections whether it's Bond the client or the server right so imagine that you have a support system a support ticketing system where you have a client asking help from support and either the actual support person or the client itself drops their websocket connection but neither the client nor the server realize what's happening and that person can be sending messages all day long and never will receive a single message again and never will actually get any of their messages sent back to them so they'd have to know whether or not to refresh the page which they'd have to restart the entire support process all over again and all of a sudden you've lost a customer for life right so what do we need to do we need to implement some sort of system and the way we're going to do it is with a ping and a pong system to check and make sure that all of your websocket connections are still active if let's get right into it all right so we're starting off with our websocket simple template and you can actually grab the link to that repo in the description below but basically we've renamed it to be websocket template because after we're done implementing this heartbeat uh it'll be a much more robust solution for actually starting with as a websocket server template and so this is going to be our actual just websocket template going forward and right now we have everything more or less in this primary index.ts server file and so we kind of want to clean that up a little bit so let's go ahead we're going to create a new folder called sockets and we are going to create a file in that folder called index.ts and inside this index.ts we're going to start kind of moving all of our socket implementation logic away from this file and into this file so let's go ahead and just move those two functions and we can export our default configure function where we're going to be passing in a single argument of type server and we actually need to import oh we actually need to add a function declaration that'll that'll help and then we need to import our server type from http all right and so in this file now we can actually see that basically everything underneath our app.listen here is more or less websocket logic so let's go ahead and copy or cut all of that out and put it inside of this configure function here so we can remove that space and then finally we can import our websocket definitions here so we have our websocket server we have our websocket and you can basically see that everything that was being done in this file is now being done in this file so we can import the configure function so you can call this whatever you want we're going to call it configure sockets and that's going to be you know from slash sockets and we can actually rename this as well to configure routes and we'll just change that there and instead of actually just declaring a variable here we can now just call our configure sockets function and we're going to pass in the entire return value of app.listen which is a server so you can see it there and it's going to go into our configure sockets function and then we'll be able to handle all of our configuration in this file from now on right and so basically what we're going to be doing is we're going to be implementing a ping and a pong more or less so we're going to kind of check every single websocket every now and then so we're going to set like an interval and on an interval we're going to basically ping every connection and expect to receive a pong back right and so there is a little bit of overhead but the overhead is more or less worth it because you don't want dead connections if you have too many dead connections you're going to be bogging down your server and sending out data that just doesn't need to be sent right and so basically what we're going to be doing here is that we want to Define an interval so let's just call it heartbeat interval and generally this is going to be something like 10 seconds you could do anywhere between 10 and 30 seconds would be kind of typical whatever the maximum delay that you'd expect from a client you know to actually potentially see right and so heartbeat interval we could say so we're going to do 1000 because it's in milliseconds and we'll just say five for now so that'll be you know five seconds and in production I probably wouldn't do five seconds because that's just too too often I'd probably do something more like 10 or 15 maybe even 30 depending on what the actual web sockets are being used for but you can go ahead and you know leave it as five for now just so that we can actually see it happening and we can see it working right and then the other thing we're gonna actually be doing is we're sending a ping value right so we could call it um you call it heartbeat value ping value uh let's just call it heartbeat value for now and we're gonna set it to one you could set it to something a little bit more um you know secretive per se uh and you know you might actually check that but we're basically sending a one down and we're going to receive we're going to expect to receive a one back right and it's gonna be sent as binary data instead of you know string or Json data right and basically um you know that's more or less what we need to do we could Define our actual ping function so let's call you know function ping and we're going to be passing in a websocket here and then what we're going to basically be doing is we're going to be sending that heartbeat value and we're going to be sending it as binary data so that's going to be our ping function sending the heartbeat value and it's going to be sent as binary so now what we need to do is we basically need to handle uh the logic in this wss.on connection right because that's when we actually get our socket right here right so what we want to do is that we want to actually specify that this socket is Alive Now typescript doesn't like the fact that we're setting a property that doesn't exist on this websocket now this websocket definition is from the Ws package so what we can do is that we can create a new folder called typings and inside typings we are going to create a new file called ws.d.ts you can name this whatever you want I like to name it the actual name of the package that we're going to be extending so we are going to import the websocket from ws and then we're going to declare the module ws and we're going to extend the interface uh web socket there we go so we're going to be extending that interface websocket right that matches up here and we're going to be specifying a is alive property that is a Boolean so if we go back we can see typescript is happy as a clam again and so we have WS that is alive set to true and the other thing that we're going to be needing to do is we're actually going to be needing to needing to Define this interval right so outside of this connection we are going to say const interval equals set interval and this interval this function we want to fire every heartbeat interval right so that's why we actually defined that heartbeat interval and so what we're going to be doing is we're going to be looping through similar to this message right here We're looping through our clients but we're not going to care whether or not the ready state is open we are just going to be looping through the clients and we're going to be checking if it is not alive then we actually want to terminate that client and return otherwise we are going to be setting client.is alive equals false and then we're going to Ping using that client so we're going to we're going to use this client to Ping basically or ping the client right so we're going to Ping the client and we're going to expect a pong all right so basically our pong is going to be received in message form but it's received as binary data so what we can do is we can actually check if it is binary right else we're going to Loop through the clients and send the message now what we can do is we can do we can get a little bit more exact and we can say you know if you know it is binary and we can just say message now this is raw data so you could actually Define it as you know something specific but I'm just going to use any for now but we're going to be indexing into the first spot and we're going to be checking the heartbeat value right so we want it to equal the heartbeat value because that's what we're going to be sending back and basically that's just a value of one and so if is binary and the data equals one then we're actually going to be you know setting the is alive property back to True right and what we can also do is we can actually log we can log pong as well so just so we can actually see it happening and seeing it work we're going to log pong and we can also actually log here as well we're going to probably comment these out before we check in any code but we want a log that we're actually firing the interval right so firing interval and so basically the way that this works is that we are establishing an interval right and every single time this interval function fires We're looping through all of our clients and we're checking if this is alive equals false now on connection we're setting the value to True right so upon connection we're setting it to true and then we're checking if it's false right which shouldn't happen the first time after a connection right and then we're setting the value to be false and then we're pinging right if we receive a pong then we're setting the value back to be true so we're setting it to false we're pinging upon pong we're setting it back to be true and that should continue to work we should never actually see any kind of race condition that's going to be an issue this should continue to work indefinitely for as long as the connection is valued now if the connection does drop for whatever reason then we will terminate the connection and we will free it up from this list of clients and we'll have one less client to actually uh loop through right so this is basically everything we really need from a server side now what we need to do is we actually need to implement this on the client so let's go ahead and go to our public folder and we'll go to our app.js here and we're going to go ahead and kind of go through exactly what we need to implement here but basically we need to create a heartbeat function so we're going to create this heartbeat function and it's going to be of type um you know websocket for now so it's going to be of type websocket and inside this heartbeat function basically what we're going to be doing is we're going to be setting this ping timeout right so basically the Ping timeout um well I guess actually we don't even need the heartbeat we don't even need because we have WS in here already so the heartbeat function will just be a function like this we don't need to pass anything in we have WS here we're only going to have a single websocket at any given time so what we want to do is we actually want to set ws.ping timeout equals set timeout and what we need to actually do is we need to make sure that this value is a match to our server so what we want to say is that we want to say our you know heartbeat interval here equals and we can say it's the 1000 times the 5 right so that'd be five seconds but what we really needed we needed to be something a little bit more than five seconds because we need a buffer right so it's going to be five plus some arbitrary buffer I'm going to say an additional one second in there now obviously you don't need this additional one but we want to be explicit and what we're doing here so it could just be you know the 1000 this is the five that we're taking and then this is our buffer right now this math is negligible so don't worry about slowing down your client at all you want to do things that are going to actually look good and be able to tell why you're actually implementing something this way so what we say is we can just say five plus one second and that's going to be our heartbeat inner so that's gonna be all right well let's call it heartbeat timeout right not heartbeat interval so it's a little bit different because we're actually doing a timeout here as opposed to an interval right so that's our heartbeat timeout and if this timeout actually does fire what we want to do is we want to close WS all right and then after that this would basically be where our business logic goes for re-establishing a connection so basically business Logic for deciding whether or not to reconnect and you may automatically reenact you may have the client have to do something to reconnect you might pop up a modal and be like are you still you know here and if so reconnect that kind of thing but again this is where you would do that and you may just automatically depending on how you actually want to implement this so in here we can actually check you know if not not WS or so you could just say if not WS return you know else if not not ws.ping timeout um that's where we actually want to clear the time out and it's going to be ws.ping timeout now I know there's some gross red squigglies everywhere that's because our websocket doesn't have this property again you could have an underscore property if you want to kind of keep it a little bit more protected um I don't think they're ever going to implement a value called ping Timeout on the native you know websocket but again you never know you're polluting you know the native objects so again you may want to underscore it or double underscore it even that's up to you right again so we need to actually tell typescript that this is what we intend to do and so let's go back to our typings folder and we're going to create a new file called index.d.ts and we're going to Define an interface called websocket EXT which is going to extend websocket and we want to create this ping timeout which if we look at what set timeout returns we can actually see it is a node.js.timeout so we're going to create it as a node.js DOT timeout and then when we Define this we are going to set it to be WS to be a websocket EXT right so again let's see if it actually allows us to do this all right so now we are saying this new websocket as a websocket EXT so now we're good to go and everything seems to be good for this right so we actually have our heartbeat function now the second thing we want to actually Define is is binary function right and it's going to be some kind of object so this could be a generic function that will always work oh but we actually we didn't finish a heartbeat function yet so forget this is binary right now we've defined our ping timeout but I forgot after we actually Define this ping timeout we actually have to send the pong right so what we want to do is we want to basically do this Palm function which is more or less just creating a you know data array so it can be a new unit array size one all right data zero is just going to equal that heartbeat value so we could have another const up here just called heart beat value equals one all right um You don't need to Define that variable but I think it's just good to kind of have it up there and then we're just going to ws.send the data right so our heartbeat function is finished now right we set this ping timeout first we clear it if it exists and then we reset it to be for this timeout now if we don't actually ever receive a ping from the server this set timeout function will fire and we will close the function man or we'll close the websocket manually right so again and then we may actually re-establish the connection if we need to but we need to actually be able to check on message whether or not the data we're receiving is binary or whether or not it's a message that we want to show right and so for these binary functions we basically just want to return the you know if type of object equals equals equals object right and we're going to do a little trick here where we're going to grab the tostring function of the object prototype right so we're going to grab this and then we're going to set the context we're going to call it with the context of the object right and so it's basically going to perform a tostring call on this object and if it equals object blob then we know that the data itself from the server is going to be binary so if it's blob data we know that it's going to be binary otherwise it's going to be something else right so it could be Json it could be a string depending on how you actually what you're actually sending right so we know we have binary data now we can actually we have all the tools that we need but we need to do a few things down here we need to actually Implement something in message we need to input something in close right so in close if our connection is closed we want to clear that time out because we don't need it anymore so if not ws.ping timeout then we're just going to clear the timeout all right so we're cleaning that up and then in message what we want to do is we want to check if is binary right message.data then we're going to do something otherwise we're going to show the message you know or handle the message as if it's an actual message right now basically what we're going to actually be doing in here is we're going to be using that heartbeat function that we have up here right so if is binary messages data we want to heartbeat right and so we call heartbeat and then that's going to pong the server and that's going to basically keep the connection alive and keep things going right so if is binary heartbeat otherwise we've received a message and that should be the whole implementation here so what we want to do is we want to go ahead and we want to pop open a terminal and we're going to go ahead and npm run Dev all right no errors that's good everything seems to be working so let's go ahead and pull open a browser real quick and we're going to localhost 3000 and actually let's let's just open a couple of those three thousands all right let's go ahead and open three of them and we're going to open up a connection first and foremost and so if we pop this back open we can actually see that we're firing the interval and we received a pong so that's good firing interval pong let's go ahead and close a lot of these files real quick and so you know basically we have our console.log pong in here and so basically you can see that we should be receiving a pong from every single client right and so um oh and actually I just noticed something one other thing we need to do is we have this interval here but what we haven't done is that we we don't want this to fire indefinitely if this websocket server were to close right and so just to clean up you know the last of it what we want to do is you want to handle the websocket server close function and you just want to clear the interval interval all right so that's just a little housekeeping and again that's actually restarting the server should close that connection so let's go ahead you can actually see the web socket connection close so that's good all right so let's go ahead open the connection back up websocket connection established all right we're firing the interval every time we're receiving a single pong here single pong now let's open up a second connection we have two connections open and now we're receiving two pongs and every time we open a connection we should receive the same number of pongs so just to kind of make sure that it's true we have a third one now and upon the next firing of interval we have three pongs and let's make sure that we can actually send a message so sent message test receive message test receive message test received message test let's just sing test two sent to receive test two this one has received test and test two and this one has received test and test two as well so everybody's receiving the data we can go ahead and we can check that we're still getting pong here and we can close a connection so if we close this connection here we will show you that the connection one connection was closed but we're still firing the interval and we're still receiving two pongs we can continue firing this interval and getting two pongs all right now you know closing out is the same thing we still have two connections here let's go ahead and just close out this browser right make sure that we now have one pong so that connection was closed and so we're still firing the interval we have a single pong still and finally we will close the final connection and you can see connection was closed firing interval no pongs left so the heartbeat function is working if we did have one drop we would automatically close that connection we could create logic to reconnect but everything is good to go and you shouldn't have any problems moving forward all right so I hope that was easy enough to understand I feel like I tried to kind of go step by step through it and we successfully created our heartbeat function and again like I said we have it set as five seconds on the template but you may want to extend that out to be something more like 10 20 or 30 depending on your particular use case but it shouldn't really bog down your servers too much it's just really not that much overhead and honestly it's necessary because like I said the other scenario is that you could potentially lose a customer forever having a very bad you know support system or support ticket in general right so again make sure you subscribe to our videos if you want any future videos we're doing more websock videos in the future making that server even better but otherwise if you have any additional content requests or content ideas feel free to drop them in the comments below we really do look at every single one of them and check out our merch store we have cool courses and as well as merch in the descriptions below just go to our website if you want to become a full stack developer take our full stack course if you want to learn more about react take a react course otherwise we'll see you soon
Info
Channel: Covalence
Views: 6,375
Rating: undefined out of 5
Keywords: Covalence, Programming, Coding, Software Development, learn to code, online coding bootcamp, intro to react, intro to javascript, intro to typescript, node.js, MySQL, .NET, React.js, free web development tutorials, software development bootcamp, web development, javascript, typescript, mern stack, express, become a programmer, how to become a software developer, programming tutorials, become a full stack developer, software careers, websockets, ws, heartbeat, dropped connections, wss, sockets
Id: cUGRlM3SZ1w
Channel Id: undefined
Length: 23min 3sec (1383 seconds)
Published: Fri Mar 17 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.