When uploading changed files to a live webserver, how do I enforce at any given moment, my entire file set is either in the old state, or new, but never something in between?
With 'in between' I mean some files old and some new, or some particular file being overwritten halfway, et cetera.
Suppose I have a directory called foo/
on my live webserver containing a framework or bunch of script files including eachother, and I need to replace a whole bunch of files at the same time. I'd call this an 'atomic update'.
The closest I can get is uploading my new foo/
directory (containing the new files) to a different name, e.g. bar/
, and then on a shell on the webserver I do:
mv foo foo-old; mv bar foo;
But this way there is still a tiny fraction of a second where foo/
doesn't exist, when the old dir has just been renamed and the new dir is about to.
Is there a 100% correct way of doing this? I guess I need some sort of 'atomic swap', to rename or swap two directory names as a single, atomic action on file system level.
In case it's OS dependent: I'm using a webserver running CentOS and got SSH access.
The simplest way to achieve a near-atomic change of directories is to use a symbolic link as your web root, which you can re-point to a different location when upgrading.
$ mkdir old
$ mkdir new
$ ln -s old live
$ ls -l
live -> old
new
old
...
$ ln -snf new live
live -> new
new
old
Changing the target of a symbolic link is actually a 2 step operation internally, unlink
followed by symlink
.
An atomic change of directories can be achieved by creating a secondary symbolic link which points to a new directory, and then renaming the new symbolic link into the old symbolic link.
$ mkdir old new
$ ln -s old live
$ ln -s new live_new
$ mv -fT live_new live
mv
command will use a single atomic operation (rename
) to overwrite the old symbolic link with a new one.
Use 2 separate hosts (physical or virtual) and route every new user from a defined moment in time to a new host which contains the upgraded website.