Build & Deploy Hooks

Last Updated October 2014

As applications are deployed on Pagoda Box, certain processes or tasks can be run in the form of Build & Deploy Hooks. These allow you to "hook" into the deploy process and execute specific scripts or commands. This can be extremely useful for tasks such as altering files for the production environment, loading dependencies, database migrations, clearing cache, or anything else your developer-brain can conjure up. After reading this doc, you should be familiar with:

  • The deploy process
  • The different types of build & deploy hooks
  • Configuring build & deploy hooks in the Boxfile

Understanding the Deploy Process

When apps are deployed on Pagoda Box, there are really two main phases of the deploy process: the build and the deploy. During the build, code is built and prepped for deploy. In the deploy phase, as the name suggests, the prepped code is deployed to new instances.

Each takes place at different stages of the deployment process. To truly grasp how and when to use build & deploy hooks, you need to understand how the entire process works.

The Deploy Process

Build Hooks

Build hooks allow you to customize the build of your code before it gets deployed to read-only instances. It's important to understand that these hooks are only for the modification of code. At this point of the process, you cannot access any of your app's data services (databases, caches, network storage). There are three different types of build hooks available to use:

before_exec
exec
after_exec

Code is Only Built Once During a Deploy

During the deploy process, your code is only built once. A single codebase is then deployed to all code services (webs & workers). Builds are not unique to each code service.

before_exec

before_exec build hooks run just after your code has been cloned into a build instance and git submodules have been loaded. These hooks can be used to prepare your code for its build process.

For example, if you have dependencies that are unique to your Pagoda environment, you can modify or replace your dependency declaration file:
mv pagoda/gemfile gemfile.

exec

exec build hooks allow you to run custom build scripts for your app. These are typically used to load dependencies into your code base. The default build exec provided by Pagoda Box loads composer dependencies. The default build execs are covered in the Composer Dependency Management doc.

Note: When using a custom build exec, if you want downloaded dependencies to persist between deploys, make sure reuse_libs is set to true and you have specified your lib_dir in your Boxfile.

after_exec

after_exec hooks run after all dependecies and submodules are loaded into your app and just before your code is deployed to read-only instances. These are great for things like like downloading remote files into your source without having to commit them to your repo, renaming files, stripping files, or even compressing javascript and css.

Configuring Build Hooks

Build hooks are configured in the build section of the Boxfile. Code is only built once, so if build actions are required for separate code services, the will all be included here.

Build Hook Timeout

You are able to define a build_hook_timeout in your Boxfile. This specifies the number of seconds a build hook will run before timing out. If a build hook times out, it will exit and the build will abort.

Build Hooks in the Boxfile YAML

  build:
    build_hook_timeout: 600
    before_exec:
      - "mv pagoda/gemfile gemfile"
    exec:
      - "bundle install"
    after_exec:
      - "curl -o js/jquery.js http://code.jquery.com/jquery-2.1.1.min.js"
/Boxfile

Deploy Hooks

Deploy hooks run after your code has been prepped and deployed to new instances. These hooks have full access to your app's data services. Deploy hooks are unique to each service. There are two different types of deploy hooks available to use:

before_deploy
after_deploy

Deploy Hooks are Past the Point of No Return

At this point in the deploy process, code has already been deployed into new instances. If any deploy hooks fail, there is no way to back out of the deploy. Hooks will either fail altogether or eventually time out. Whatever state the hooks leave the instances in will be deployed.

before_deploy

before_deploy hooks run after your prepped code has been pushed to new instances, but before traffic has been routed to the new instances. In this phase of the process, traffic is still handled by the "old" instances, but the new instances have access to and can interact with your app's data services. before_deploy hooks are handy for things like database migrations and unit tests. In multi-instance services, these hooks only run on a single instance.

before_deploy_all

before_deploy_all hooks are the same as before_deploy hooks, except they run on all instances in the service. They become really handy when using nonpersistent writable directories, which are stored in the local filesystems of each instance. If a hook needs to interact with a nonpersistent writable directory, it needs to be in a before_deploy_all hook.

after_deploy

after_deploy hooks run after traffic has been routed to your new instances. They are handy for things like clearing your cache. In multi-instance services, these hooks only run on a single instance.

after_deploy_all

after_deploy_all hooks are the same as after_deploy hooks, except they run on all instances in the service. If a hook needs to interact with a nonpersistent writable directory, it needs to be in a after_deploy_all hook.

Configuring Deploy Hooks

Deploy hooks are handled per service in your Boxfile. Each hook should be nested under the service on which it will run. When deploy hooks run, they will have access to and be subject to the settings and configuration of that service.

Deploy Hook Timeout

You are able to define a deploy_hook_timeout in your Boxfile. This specifies the number of seconds a deploy hook will run before timing out. If a deploy hook times out, it will exit and the build will move on as if the hook completed successfully.

Deploy Hooks in the Boxfile YAML

  web1:
    deploy_hook_timeout: 600
    before_deploy:
      - "php artisan migrate"
    before_deploy_all:
      - "php scripts/clear_cache.php"
    after_deploy:
      - "bash checksum.sh"
    after_deploy_all:
      - "bash scripts/prime_cache.sh"

  web2:
    deploy_hook_timeout: 600
    before_deploy:
      - "php artisan db:seed"
    before_deploy_all:
      - "php scripts/clear_cache.php"
    after_deploy:
      - "bash checksum2.sh"
    after_deploy_all:
      - "bash scripts/prime_cache.sh"
/Boxfile

Note only certian executables are available to services and therefore deploy hooks. The Available Executables doc lists the most commonly used executables available to deploy hooks.

Things to Know About Build & Deploy Hooks

Hooks Run from the Root of Your Repo

Both build & deploy hooks are run from the root of your repo. For specific filepaths, you can use the relative path or the absolute server path (/data) in your command.

Disable Any Interactivity

If there is any interactivity in your build or deploy hooks, you will need to disable it. There is no way to interact with a hook during the deploy process.

Modifications to Data Cannot Be Rolled Back

Any modifications deploy hooks make to data within data services (databases, network storage, caches) cannot be rolled back. It would be wise to have backups before running a deploy hooks that modifies data.

If you have any questions, suggestions, or corrections, let us know.