Castle

Runtime support for hot-code upgrades.

Castle provides runtime support for hot-code upgrades. In particular, it generates a valid sys.config from runtime.exs and/or other Config Providers prior to both boot and hot-code upgrade.

It relies on Forecastle for build-time release generation and brings it in as a build-time dependency.

Installation

The package can be installed by adding castle to your list of dependencies in mix.exs. For projects that don't define a release, but use the appup compiler, it's sufficient to bring Castle in as a build-time dependency:

def deps do
  [
    {:castle, "~> 0.3.0", runtime: false}
  ]
end

For projects that do define one or more releases, Castle should be brought in as a runtime dependency:

def deps do
  [
    {:castle, "~> 0.3.0"}
  ]
end

Castle brings in Forecastle as a build-time dependency.

Integration

Build-time integration is done via Forecastle and more details can be found in its documentation but, in summary, it will integrate into your release process via the release assembly process. In particular, it requires that that the Forecastle.pre_assemble/1 and Forecastle.post_assemble/1 functions are placed around the :assemble step, e.g.:

defp releases do
  [
    myapp: [
      include_executables_for: [:unix],
      steps: [&Forecastle.pre_assemble/1, :assemble, &Forecastle.post_assemble/1, :tar]
    ]
  ]
end

Release Management

The script in the bin folder supports some extra commands to manage upgrades. Releases, in their tarred-gzipped form, should first be copied to the releases subfolder on the target system. The following commands can be used to manage them:

The Appup Compiler

You are responsible for writing the appup scripts for your application, but Castle will copy the appup into the ebin folder for you. The steps are as follows:

  1. Write a file, in Elixir form, describing the application upgrade. e.g.:
    # You can call the file what you like, e.g. appup.ex, 
    # but you should # keep it away from the compiler paths.
    {
     '0.1.1',
      [
       {'0.1.0', [
         {:update, MyApp.Server, {:advanced, []}}
       ]}
      ],
      [
       {'0.1.0', [
         {:update, MyApp.Server, {:advanced, []}}
       ]}
      ]
    }
    This file will typically be checked in to SCM.
  2. Add the appup file to the Mix project definition in mix.exs and add the :appup compiler.
    # Mix.exs
    def project do
      [
        appup: "appup.ex", # Relative to the project root.
        compilers: Mix.compilers() ++ [:appup]
      ]
    end

Relup Generation

Castle contains a mix task, castle.relup, that simplifies the generation of the relup file. Assuming you have two unpacked releases e.g. 0.1.0 and 0.1.1 and you wish to generate a relup between them:

> mix castle.relup --target myapp/releases/0.1.1/myapp --fromto myapp/releases/0.1.0/myapp

If the generated file is in the project root, it will be copied during post-assembly to the release.