Laravel solved race conditions

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
here we've got four processes fighting over the same resource but because we're using laravel's Atomic locks only one of these processes is going to get access to the resource at a time whether that's looking for the next import or processing a podcast or making sure that some script is only running on one server at a time and not a bunch of different servers laravel's Atomic locks give us a nice easy way to pull this off without having to worry about race condition let me show you how we've done it I've got a standard LEL command here I've emptied out a bunch of the comments and then just added a render function that's going to render our red green backgrounds I'll show you that in a little bit but before we do we got to talk about this Locking System a a locking an atomic Locking System is a way to communicate to other processes that I'm in charge I'm the captain now I'm the only one that's allowed to do this thing in laravel the Locking System is built into the cachier system so you have to have a compatible cash driver so if you do cash you'll see that lock is part of the cash name space or the cash facade in this case now there are several compatible cach drivers that work surprisingly database and file work and then stuff you you would probably expect like redis and mimc the array driver is listed but there's a big caveat to that um which we will talk about in a little bit but you have to have a compatible Cash Drive driver and if you want to communicate across servers everyone needs to be talking to the same cache driver so the first thing you would do is you would give it a name you could give it something silly like example or like we were talking about earlier if you want one process to be in charge of processing a single podcast you can name it like that or you could name it um let's say you've got 10 import uh processes running and you want to make sure that only one is pulling import off of the que at a time that is something that I've definitely done we're just going to name ours example and then you say how long do you want to keep this lock for you can manually release the lock but in the event that your process dies how long should this lock be held before it expires that's it now you have now you have the beginnings of a lock and now what we can do is we can say lock get and if we want to just pass a call back in we can say this line got the lock and that should be enough now we know we're the only process that is going to be doing this thing at a time now in real life this would be some sort of long process where you're calling out to an API to publish the podcast or you're doing something with an import to mark it as you know started or working but we're just going to say got the lock if we switch over and we do PHP Artisan my short hand is AR so that's PHP Artisan app run you'll see got the lock got the lock got the the lock not very interesting and maybe a little bit confusing cuz I told you that the lock lasts for 10 seconds unless you release it well if you pass a call back the lock automatically gets released at the end of the call back so we can say let's say acquired if acquired then we'll say this line got the lock else we'll say let's just say Sad no lock for you so if we switch back now what we're going to see is the first time the first time we run this we got the lock and then for a while it's just going to say Sad until the lock expires after 10 seconds which should be there you go I was I was going to see how long I had to Vamp there you go so the lock expired we never actually manually released it and it didn't automatically get released it just expired and so now this process has the lock and that was 10 seconds so now you'll see now we're just waiting for the lock to be be released so you can take that lock and pass it around and you can decide when you want to release it or you can pass a closure through and it will be released at the end of that closure this doesn't make for a very compelling example when you're only working with one process right because there's no one competing against you but when there are multiple processes or multiple processes on multiple servers that's when you need to start communicating and say hang on everybody I'm working on this thing y'all don't start working on it I need to go in and claim my resources and then I'll give the lock back and y'all can start looking for resources that you should be working on I'm going to move all the rendering down to this render function and I actually like the name acquired better so we're going to do that we can get rid of this guy let's take got the lock come down here so if it's acquired we'll say got the lock otherwise we'll say Sad then we can say this render acquired if it is acquired we're going to sleep for about 3 seconds well exact L 3 seconds in fact just to mimic some processing so we'll say sleep for a bit and then we're going to release the lock so this is how we would manually release the lock remember it will expire after 10 seconds but once we're done processing whatever it is we're processing we're going to release the lock and let the other um servers or processes start doing their work if we run this now so if we clear this out and we run that you'll see it's going to sleep for about 3 seconds and then it's going to end right so this is pretty much working we can flip back over to where I have four set up and run one run one real fast and if we're fast enough there we go run the other so the one on the left locked the it acquired the lock and the one on the right did not and so it was sad and we'll do it vice versa there we go now we got to start running this thing in a loop cuz this is way too slow for me to be doing manually let's not only do a loop Let's do an infinite Loop we don't we don't get to do these very often so let's do a w one wrap the whole thing up in a wow one let's throw a little bit of a sleep at the top here so we'll do a random between one and 5 time 50,000 that's just going to be just a little bit of sleep so we're not totally maxed out the whole time if we switch back over we'll clear this guy out clear this guy out and app run got the lock app run sad oh there we go and there we go so now we're switching back and forth we can actually do more why not let's do a whole bunch more we're switching back and forth between now four processes but you'll see only one gets the lock at a time and this is exactly what we're looking for we don't want to run to uh commands on on a server at a time we just want to run the one and that's what Atomic locks give us now let's let's make this let's make this prettier we're getting a little bit away from Atomic locking and into making this making this demo really pretty but I did like the red and green background so let's do that real fast I have a package installed called term wind which gives you kind of Tailwind but in your terminal so what I'm going to do is I'm going to say the background color is if it's acquired give me BG green 600 if the lock was not acquired give me BG red 600 and then the divs are going to be let's do a string repeat um so the string is going to be uh we're just going to do a div with a non-breaking space in the middle and we'll say class equals W full kind of wild that you can do this in the terminal class equals W full with the background and we want to repeat it terminal height I think that's right and so now we can say in instead of this line we're going to use term wins render function and we're just going to wrap the whole thing in a div and throw out a new there we go I think that should be all we need to do let's go ahead and just run it and see what happens hey there's a green background and there's a red background there's a red background there we go we're back to our demo it does look if you notice if you look really really closely it does look like the lock is shared there for a second and that is actually just a rendering problem that is not a lock problem the locks are Atomic what happens is we release the lock the background stays green and then we sleep for up to 250 milliseconds with a green background so we just need to render so if we render now we know for sure that we don't have the lock because we just released it so we're going to release or we're going to render false and we can run back here and say run run run and run now we should see completely Atomic switching with no overlap whatsoever it's actually kind of fun to watch I do I do enjoy watching this we need to talk about the drivers for a second it is very important if you're trying to coordinate across different processes that all processes are talking to the same driver so they're all talking to the same redis connection or the same database or the same file system if you're going to use the file driver you can't use it on two separate servers that have different file systems let me show you what happens if you do try to do that so instead of using the file I'm here on my local computer that's fine you can use the array the array is only really useful for testing because if you use the array driver the cash the cache is basically in memory it's in an array in memory and each different process has its own so you'll see now that if we run this it's just pure chaos everybody gets a lock you get a lock you get a lock and you get a lock the only time something is not locked is the microsc after it's released before it acquires it again so technically all four of these processes have acquired a lock but they've acquired an inmemory lock that is completely isolated from the other three and so they're all just they're all just happy thinking ah I've got the lock well yeah everybody has a lock so be careful what driver you choose now in terms of the database you may be thinking I don't know that feels weird I don't know much about database locking it's probably some advisory lock or shared lock or some sort of database lock thing that scares me right not really the the beautiful part about the way that larl has implemented the atomic locks in the database driver is it actually doesn't use the database locking mechanism at all my SQL has like this get shared lock so you can you can kind of do this thing in my SQL that's not what that's not what laravel uses at all instead larl inserts a single row so it works with every single database driver for sure let me show you how this works if we switch back here and we switch the cach driver to database let's go ahead and just run a few it doesn't we don't we don't need all of them if we just run one here and one here we should see those bounce back and forth between the two so we know that it is working now if we look at the database we'll see we have this cach locks table and this is a laravel laravel gives you the migration to do this so you don't have to come up with this yourself but the only thing that is going on in this table is there is a key and the key is unique this key column is unique and what laravel does is it inserts you can see larel cach and then the name of the key that we gave it which is example it inserts it just inserts the row and because databases are pretty good at making sure that if you say this is a unique column they're pretty good at making sure that only unique values get in there this is the way that laravel accomplishes Atomic locking with a database driver it relies on primary key enforcement so a little bit of trivia all that to say don't be scared of the database driver for driving your Atomic locks it's not doing anything special it's relying on the database's natural ability to enforce a primary key constraint we've only barely scratched the surface here there there's a lot more that you can do one of the more interesting things that you can do is you can you can acquire the lock and then it gives you an identifier that you can pass to another process to reinstantiate the ownership of the lock and so you can acquire a lock in one process and release it in a second second process that's a little bit of an advanced example but it can be very useful especially if you're passing a lock into a job that is going to be processed later how do Locks and locking relate to jobs and cues is a good question I think it it operates entirely outside of it the cues are very robust and the cues are good at making sure that jobs get pulled off and processed one time this is kind of entirely separate when you need to do something else and you want to ensure that only one process or one server is doing that thing the way that I have used it in the past is I've had many many worker processes waiting around for users to import csvs and when the users import a CSV I only want one worker to pick it up one worker is going to pick it up but I have five workers running so I just have each one acquire a searching lock so every worker acquires a lock that says look out guys I'm going to go search for imports now y'all don't do it and if I find one I am going to mark it as reserved so anytime you need to do one thing across multiple processes or multiple servers you might reach for Atomic locks they are very cool the docks are very good I would encourage you to check them out see you
Info
Channel: Aaron Francis
Views: 14,741
Rating: undefined out of 5
Keywords:
Id: jGb5zIgwL4c
Channel Id: undefined
Length: 14min 12sec (852 seconds)
Published: Fri Nov 10 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.