/forecastle

Primary LanguageElixirMIT LicenseMIT

Forecastle

Build-time support for hot-code upgrades.

Forecastle provides build-time support for the generation of releases that correctly support hot-code upgrades. This includes:

  • Copying appup and relup files into place.
  • Organising the generated release structure so that it's ready for hot-code upgrades.
  • Replacing the shell script with one that supports release unpacking and installtion

Additionally, Forecastle ships with a appup compiler and a mix task for relup generation.

Installation

Forecastle is not intended to be taken as a direct dependency. Most applications should prefer to take a dependency on Castle directly which will, in turn take a build-time dependency on Forecastle.

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

Integration

Forecastle integrates into the steps of the release assembly process. It requires 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

Build Time Support

The following steps shape the release at build-time:

Pre-assembly

In the pre-assembly step:

  • The default evaluation of runtime configuration is disabled. Forecastle will do its own equivalent expansion into sys.config prior to system start, first with runtime.exs (if it exists) and then with any Config Providers.
  • A 'preboot' boot script is created that starts only Forecastle and its dependencies. This is used only during the aforementioned expansion.

The system is then assembled under the :assemble step as normal.

Post-assembly

In the post-assembly step:

  • The sys.config generated from build-time configuration is copied to build.config.
  • The shell-script in the bin folder is replaced with one that provides additional commands to manage releases.
  • Any runtime.exs is copied into the version path of the release.
  • The generated name.rel is copied into the releases folder as name-vsn.rel.
  • Any relup file is copied into the version path of the release.

The Appup Compiler

You are responsible for writing the appup scripts for your application, but Forecastle 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.exs,
    {
     '0.1.1', # Code is eval'd so can also: to_charlist(Mix.Project.config[:version]),
      [
       {'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.exs", # Relative to the project root.
        compilers: Mix.compilers() ++ [:appup]
      ]
    end

Relup Generation

Forecastle contains a mix task, forecastle.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 forecastle.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.