Atomic Symlink Changes
A common deploy strategy for a lot of web sites is as follows
v1.0.10 v1.0.11 v1.1.0 current -> v1.1.0
So in this directory we have three directories and one symlink. The directories contain our web application and are tagged with the source control version they were tagged with by the developers. Now its a common practice when deploying a new version to upload the new release which will be v1.1.1 and then just change the symlink to point to the new location. That really isn’t a great idea.
Sure it will work for 99.9% of your traffic but if you have a busy website it could really effect users as your do the upgrade. You are probably saying well I’m forcing the new symlink with the following command
ln -snf v1.1.1 current
Did you ever look at the system calls using the -f flag for ln does? If not lets take a look
# strace ln -snf v1.1.1 current 2>&1 | grep link symlink("v1.1.1", "current") = -1 EEXIST (File exists) unlink("current") = 0 symlink("v1.1.1", "current") = 0
So you can see it first tries to create the link and finds the symlink is there so it unlinks curent and makes the new symlink. The man page even says this is the case!
-f If the target file already exists, then unlink it so that the link may occur. (The -f option overrides any previous -i options.)
So how do we make this more atomic so that our users do not even notice and everyone is happy? Well its very simple.
ln -s v1.1.1 current.new && mv -Tf current.new current
That will do an atomic update. If you want to learn more about the -T flag you can find it here
It might not be 100% atomic but it’s really the best I can get right now. POSIX says its atomic so right now I’ll trust it.