December 16, 2014

WordPress on Heroku with HHVM

How to

The instructions worked me, and I installed WP’s DB and set up my admin user.

Now it gets weird

I added the WordPress importer plugin so I could transfer my posts, and the Independent Publisher theme to composer.json like this:

"require": {
        "hhvm": "~3.2",
        "WordPress/WordPress": "*",
        "wpackagist-plugin/jetpack": "~3.1",
        "wpackagist-plugin/wpro": "~1.0",
        "wpackagist-plugin/sendgrid-email-delivery-simplified": "~1.3",
        "wpackagist-plugin/authy-two-factor-authentication": "~2.5",
        "wpackagist-plugin/wordpress-importer": "*",
        "wpackagist-theme/independent-publisher": "1.6"

    },

Since composer.lock is included in my repo, just re-deploying the site will not make composer install the new dependencies from composer.json. Why? Composer looks to composer.lock first because it has the exact versions of the packages to install. There are two workarounds:

  1. Remove composer.lock from Git repo
  2. Update composer.json AND composer.lock on some machine before committing to Git and deploying on Heroku

Remove composer.lock from Git repo?

This is easy, but not recommended because:

  1. Deploys will take longer and use more memory as the exact versions of all dependencies in composer.json will have to be resolved on every deploy
  2. Developers and production servers may end up with different composer.lock files, potentially resulting in everyone having out-of-sync dependencies

I wrote more about versioning composer.lock here.

Update both files before deploying?

Because "hhvm": "~3.2", is included in the required dependencies, composer update must be run using HHVM instead of PHP. That means I need an install of HHVM outside of Heroku just to update composer.lock

HHVM requires a 64 bit Unix-like operating system. It will not run on my Windows dev machine, nor a 32-bit Linux VM which is what my dev machine is capable of running. Time to upgrade?

Temporary Solution

For now, I have to follow this workflow to add a new dependency in composer.json:

  1. Remove "hhvm": "~3.2", from composer.json

  2. Run composer update on my dev box without HHVM installed

  3. Add "hhvm": "~3.2", back to composer.json for Heroku’s sake

  4. Commit composer.lock and composer.json to Git and deploy

HHVM will not appear in composer.lock, but that’s OK. Heroku still runs it.

Update after deploying?

This was tempting:

  1. Use heroku run bash to fire up another dyno with a CLI
  2. Update composer.lock in there
  3. Commit composer.lock to Git and push it
  4. Redeploy the site and get new dependencies when composer install runs

But I found the command hhvm ``which composer`` update throws an error:

Loading composer repositories with package information
Updating dependencies (including require-dev)
SlowTimer [5000ms] at curl: http://wpackagist.org/p/providers-old$77702c9f39565428994a020971d129f042db127809c1caa49589ce0862e93278.json
SlowTimer [5000ms] at curl: http://wpackagist.org/p/providers-old$77702c9f39565428994a020971d129f042db127809c1caa49589ce0862e93278.json



  [Composer\Downloader\TransportException]
  The "http://wpackagist.org/p/providers-old$77702c9f39565428994a020971d129f0
  42db127809c1caa49589ce0862e93278.json" file could not be downloaded: Failed
   to open http://wpackagist.org/p/providers-old$77702c9f39565428994a020971d1
  29f042db127809c1caa49589ce0862e93278.json (Operation timed out after 4949 m
  illiseconds with 2592872 out of 4680293 bytes received)

What about composer’s --ignore-platform-reqs ?

composer update --ignore-platform-reqs will get the update command to run locally for me, but the resulting composer.lock file is not suitable to run on Heroku. The app displays an error in browser, and running heroku logs shows that the deployment did not go smoothly:

2014-12-16T14:29:53.818251+00:00 app[web.1]: app_boot.sh: 23: app_boot.sh: vendor/bin/heroku-hhvm-nginx: not found<

How did Heroku + HHVM perform?

Browsing through posts and pages was faster than on my current shared hosting (with neither install using caching). Performance in the admin area was about the same, which is where I wanted to see the most improvement.