jpriddle

/work / MWP Lazy Upgrader

MWP Lazy Upgrader

Pressed, LLC

Senior Developer

Dec 2016 ·
PHP WordPress Bash WP-CLI

MWP Lazy Upgrader is a custom WordPress plugin that improves performance for theme and plugin upgrades on a network filesystem. On network filesystems, these operations are slow and can timeout for users in WP Admin. Lazy Upgrader works around these limitations by deferring filesystem writes to a background job and using symbolic links to install themes and plugins instantly once source files are available over the network.

Background

At Pressed I was approached with a unique and challenging problem: speeding up WordPress plugin upgrades on a new version of our hosting platform.

This turned out to be one of the most challenging features I’ve shipped in my career. Before I started, I knew virtually nothing about how WordPress upgrades plugins. I had no idea how I would go about fixing things, or if I even could. It took a lot of trial an error, but I was eventually able to identify the slow parts of the process and significantly improve overall upgrade speed. It took approximately 8 weeks, on and off, from the time I was asked to look into this until it was shipped.

WordPress stores all user files (plugins, themes, image uploads) under a publicly accessible directory named wp-content/. Some plugins include thousands of files. Upgrading a plugin involves a lot of reading and writing to disk, and the number of operations increases with each file. This isn’t normally much of an issue and upgrades still happen reasonably fast.

On our new platform, the wp-content/ directory is on a network filesystem. This offers a lot of flexibility for scaling and redundancy, but it comes at a cost. Reading and writing files can be especially slow compared to traditional hardware. The hosting platform has extensive caching, so performance isn’t lost in most cases. Except one: the disk intensive task of upgrading a plugin.

LazyUpgrader is a Must-Use plugin that alters the behavior of the WordPress upgrader to work more efficiently on a network filesystem.

It works by hooking into the way WordPress loads its filesystem class, WP_Filesystem_Direct. Any file operations (like PHP’s rename(), copy(), and friends) performed by WordPress core uses this class. LazyUpgrader overwrites some methods on this class to change their behavior for usage on our platform.

The normal upgrade process looks something like this:

Most of these actions are disk intensive and slow on a network filesystem. LazyUpgrader optimizes these in two main ways:

  1. The use of additional directories that reside on the local filesystem and the network filesystem. Files are moved or symlinked here to short circuit parts of the normal upgrade process.
    • wp-content/upgrade/ is a symlink to something like /tmp/user/.upgrade
    • wp-content/.upgrade-moving is a symlink to /tmp/user/.upgrade-moving
    • wp-content/plugins/.trash is a symlink to /tmp/user/.trash
    • wp-content/plugins/.moving is a regular directory on the network filesystem
  2. After the user thinks the upgrade process is complete, cleanup happens in the background that replaces symlinks with their real versions and deletes old files

The new “lazy” upgrade process with LazyUpragder looks like this:

In benchmarks I ran on popular plugins with 1000+ files, a normal upgrade on the network filesystem took over 2 minutes to finish. With LazyUpgrader the, the user perceives that upgrade as finishing in 30 seconds.

LazyUpgrader is definitely a hack. Like the best hacks though, it solved the problem as quickly as possible. It is currently in production and working reliably for thousands of WordPress sites and will serve as a nice stop gap until a more robust solution is necessary.