That’s right, ExpressionEngine finally has a one-click updater.
All 7,000+ lines of the new updater code were written wondering what it was going to be like to ship 4.0.1, our first in-app update. Well, it seems to have gone off without a hitch! We’ve since delivered hundreds of in-app updates with, as far as we know, a 100% success rate. But it wasn’t luck, it took much deliberation to achieve those stats.
When I was presented with the task of writing a one-click updater from scratch, it was daunting. In addition to the sheer technical challenge, it’s a feature that has the power to make sweeping changes to the file system and database. It’s an enormous responsibility, not only with a site’s data and uptime, but with our customers’ trust. It has to work well.
The benefit of not being first to market with this feature is that there have already been many attempts to solve this problem. There are many documented cases of failed automated CMS updates out there on forums and Stack Overflow, we just had to go learn from them.
What became clear was that updating is scary, and that when an update blew up, the user was left with a feeling of helplessness, having to take to the internet while their site was down. So how do we (a) prevent things from blowing up in the first place? and (b) empower the customer to fix things on the off-chance that something does blow up?
Using this combination of empathy-driven and explosion-averse engineering, here are a few key decisions we made to make our updater one of the best.
Use Resources Sparingly
One of the most common complaints of in-app updaters is they run out of memory or exceed some time limit. So it was clear we needed to break up the large task of updating into small, bite(byte?)-sized chunks. Downloading is its own task, unpacking is its own task, verifying file integrity is its own task, and so on.
This presented a problem with database backups. For certain backwards-incompatible changes, we want to make database backups in case something happens and the update needs to be rolled back. But what if the data we need to back up is a bazillion gigabytes? We ended up creating a backup utility that could backup a database of any size on limited resources, provided you at least have the disk space. We did this by splitting the backup into small chunks per web request. This ended up working so well, even better than phpMyAdmin for large databases, that we made it available as a standalone utility in the control panel.
Another potentially resource-intensive task is updating ExpressionEngine’s files. Some updaters copy their new files into place, but users would report more failures if there were a lot of files to update, due to the increased time and memory usage. We solved this simply by moving files instead of copying. Moving files takes a fraction of the resources needed to copy, and since we only have to move the root folders, updating the files stays fast and lightweight no matter how many files need updating.
Empower the Customer
We’re all familiar with holding our breath before clicking that Update button. What if it fails? What state does that leave my site in? How do I roll back? Is my site going to be down until I get some help? Clicking Update should be exciting, not fill you with anxiety and uncertainty.
The updater was engineered from the beginning to catch as many preventable failures as possible and provide you with actionable steps to solve them. But if something unexpected happens, we offer a one-click rollback action that should put your install back exactly the way you had it. We achieve this through performing the actual upgrade through an independent micro-app that sits outside your ExpressionEngine install. This way, for example, if moving the new files into place fails and leaves some files updated and some not, we have a known good set of code we can run to set things straight again.
But what if even that fails? In that rare case, the customer should be able to get themselves up and running again with just a few steps and no feeling of helplessness. Move a few files around, optionally import a database backup, and you are back in business. Plus you always have the option of performing a two-folder manual upgrade à la ExpressionEngine 3.
Not only do these steps keep the customer in control, but it reduces our support load. Having released a few updates to ExpressionEngine 4, so far we have not had one support request for a failed update. And over half of all v4 production sites are either on the latest patch release or only one patch release behind.
Security is an important selling point of ExpressionEngine, and as you can expect, we’ve brought that same consideration to the updater. For instance, we’ve included a command-line updater if you prefer extra control over your file permissions. But there’s one more, big, security problem to solve.
The updater is essentially an automated process that downloads code from somewhere and then executes it on your server. What if that code isn’t ours? What if someone is able to fool ExpressionEngine into downloading and executing someone else’s code on your server?
We did a lot of research into the best practices for secure code delivery, and arrived at a cryptographic signing system so that ExpressionEngine knows it’s getting code from us and only us. Some popular PHP package delivery systems are behind in this area, and one popular CMS is currently vulnerable to one of the largest remote code execution attacks the world has ever seen. Sleep well tonight.
Keep Calm and Update
One of my favorite quotes is “make the right thing easy.” It can be applied to many facets of life, but is particularly useful in software design. Having the latest features, stability fixes, and security patches should be easy. We hope this feature goes a long way in reclaiming your valuable time and ultimately makes updating a delight.