The application upgrade file defines how an application is upgraded or downgraded in a running system.
This file is used by the functions in systools
when
generating a release upgrade file relup
.
The application upgrade file should be called
Application.appup
where Application
is the name of
the application. The file should be located in the ebin
directory for the application.
The .appup
file contains one single Erlang term, which
defines the instructions used to upgrade or downgrade
the application. The file has the following syntax:
{Vsn, [{UpFromVsn, Instructions}, ...], [{DownToVsn, Instructions}, ...]}.
Vsn = string()
is the current version of
the application.UpFromVsn = string()
is an earlier version of
the application to upgrade from.DownToVsn = string()
is an earlier version of
the application to downgrade to.Instructions
is a list of release upgrade
instructions, see below. It is recommended to use
high-level instructions only. These are automatically
translated to low-level instructions by systools
when
creating the relup
file.Release upgrade instructions are interpreted by the release handler when an upgrade or downgrade is made. For more information about release handling, refer to OTP Design Principes.
A process is said to use a module Mod
, if
Mod
is listed in the Modules
part of the child
specification used to start the process, see supervisor(3)
.
In the case of gen_event, an event manager process is said to use
Mod
if Mod
is an installed event handler.
High-level instructions
{update, Mod} {update, Mod, supervisor} {update, Mod, Change} {update, Mod, DepMods} {update, Mod, Change, DepMods} {update, Mod, Change, PrePurge, PostPurge, DepMods} {update, Mod, Timeout, Change, PrePurge, PostPurge, DepMods} {update, Mod, ModType, Timeout, Change, PrePurge, PostPurge, DepMods} Mod = atom() ModType = static | dynamic Timeout = int()>0 | default | infinity Change = soft | {advanced,Extra} Extra = term() PrePurge = PostPurge = soft_purge | brutal_purge DepMods = [Mod]
Synchronized code replacement of processes using the module
Mod
. All those processes are suspended using
sys:suspend
, the new version of the module is loaded and
then the processes are resumed using sys:resume
.
Change
defaults to soft
and defines the type of
code change. If it is set to {advanced,Extra}
, processes
implemented using gen_server, gen_fsm or gen_event will transform
their internal state by calling the callback function
code_change
. Special processes will call the callback
function system_code_change/4
. In both cases, the term
Extra
is passed as an argument to the callback function.
PrePurge
defaults to brutal_purge
and controls
what action to take with processes that are executing old code
before loading the new version of the module. If the value
is brutal_purge
, the processes are killed. If the value is
soft_purge
, release_handler:install_release/1
returns {error,{old_processes,Mod}}
.
PostPurge
defaults to brutal_purge
and controls
what action to take with processes that are executing old code
when the new version of the module has been loaded. If the value
is brutal_purge
, the code is purged when the release is
made permanent and the processes are killed. If the value is
soft_purge
, the release handler will purge the old code
when no remaining processes execute the code.
DepMods
defaults to [] and defines which other modules
Mod
is dependent on. In relup
, instructions for
suspending processes using Mod
will come before
instructions for suspending processes using modules in
DepMods
when upgrading, and vice versa when downgrading.
In case of circular dependencies, the order of the instructions in
the appup
script is kept.
Timeout
defines the timeout when suspending processes.
If no value or default
is given, the default value for
sys:suspend
is used.
ModType
defaults to dynamic
and specifies if
the code is "dynamic", that is if a process using the module does
spontaneously switch to new code, or if it is "static".
When doing an advanced update and upgrading, the new version of a
dynamic module is loaded before the process is asked to change
code. When downgrading, the process is asked to change code before
loading the new version. For static modules, the new version is
loaded before the process is asked to change code, both in
the case of upgrading and downgrading. Callback modules are
dynamic.
update
with argument supervisor
is used when
changing the start specification of a supervisor.
{load_module, Mod} {load_module, Mod, DepMods} {load_module, Mod, PrePurge, PostPurge, DepMods} Mod = atom() PrePurge = PostPurge = soft_purge | brutal_purge DepMods = [Mod]
Simple code replacement of the module Mod
.
See update
above for a description of PrePurge
and
PostPurge
.
DepMods
defaults to [] and defines which other modules
Mod
is dependent on. In relup
, instructions for
loading these modules will come before the instruction for loading
Mod
when upgrading, and vice versa when downgrading.
{add_module, Mod} Mod = atom()
Loads a new module Mod
.
{delete_module, Mod} Mod = atom()
Deletes a module Mod
using the low-level instructions
remove
and purge
.
{add_application, Application} Application = atom()
Adding an application means that the modules defined by
the modules
key in the .app
file are loaded using
add_module
, then the application is started.
{remove_application, Application} Application = atom()
Removing an application means that the application is stopped,
the modules are unloaded using delete_module
and then
the application specification is unloaded from the application
controller.
{restart_application, Application} Application = atom()
Restarting an application means that the application is
stopped and then started again similar to using the instructions
remove_application
and add_application
in sequence.
Low-level instructions
{load_object_code, {App, Vsn, [Mod]}} App = Mod = atom() Vsn = string()
Reads each Mod
from the directory App-Vsn/ebin
as
a binary. It does not load the modules. The instruction should be
placed first in the script in order to read all new code from file
to make the suspend-load-resume cycle less time consuming. After
this instruction has been executed, the code server with the new
version of App
.
point_of_no_return
If a crash occurs after this instruction, the system cannot
recover and is restarted from the old version of the release.
The instruction must only occur once in a script. It should be
placed after all load_object_code
instructions.
{load, {Mod, PrePurge, PostPurge}} Mod = atom() PrePurge = PostPurge = soft_purge | brutal_purge
Before this instruction occurs, Mod
must have been loaded
using load_object_code
. This instruction loads the module.
PrePurge
is ignored. See the high-level instruction
update
for a description of PostPurge
.
{remove, {Mod, PrePurge, PostPurge}} Mod = atom() PrePurge = PostPurge = soft_purge | brutal_purge
Makes the current version of Mod
old.
PrePurge
is ignored. See the high-level instruction
update
for a description of PostPurge
.
{purge, [Mod]} Mod = atom()
Purges each module Mod
, that is removes the old code.
Note that any process executing purged code is killed.
{suspend, [Mod | {Mod, Timeout}]} Mod = atom() Timeout = int()>0 | default | infinity
Tries to suspend all processes using a module Mod
. If a
process does not respond, it is ignored. This may cause
the process to die, either because it crashes when it
spontaneously switches to new code, or as a result of a purge
operation. If no Timeout
is specified or default
is
given, the default value for sys:suspend
is used.
{resume, [Mod]} Mod = atom()
Resumes all suspended processes using a module Mod
.
{code_change, [{Mod, Extra}]} {code_change, Mode, [{Mod, Extra}]} Mod = atom() Mode = up | down Extra = term()
Mode
defaults to up
and specifies if it is an
upgrade or downgrade.
This instruction sends a code_change
system message to
all processes using a module Mod
by calling the function
sys:change_code
, passing the term Extra
as argument.
{stop, [Mod]} Mod = atom()
Stops all processes using a module Mod
by calling
supervisor:terminate_child/2
. The instruction is useful
when the simplest way to change code is to stop and restart the
processes which run the code.
{start, [Mod]} Mod = atom()
Starts all stopped processes using a module Mod
by calling
supervisor:restart_child/2
.
{sync_nodes, Id, [Node]} {sync_nodes, Id, {M, F, A}} Id = term() Node = node() M = F = atom() A = [term()]
apply(M, F, A)
must return a list of nodes.
The instruction synchronizes the release installation with other
nodes. Each Node
must evaluate this command, with the same
Id
. The local node waits for all other nodes to evaluate
the instruction before execution continues. In case a node goes
down, it is considered to be an unrecoverable error, and
the local node is restarted from the old release. There is no
timeout for this instruction, which means that it may hang
forever.
{apply, {M, F, A}} M = F = atom() A = [term()]
Evaluates apply(M, F, A)
. If the instruction appears
before the point_of_no_return
instruction, a failure is
caught. release_handler:install_release/1
then returns
{error,{'EXIT',Reason}}
, unless {error,Error}
is
thrown or returned. Then it returns {error,Error}
.
If the instruction appears after the point_of_no_return
instruction, and the function call fails, the system is
restarted.
restart_new_emulator
Shuts down the current emulator and starts a ne one. All processes are terminated gracefully. The new release must still be made permanent when the new emulator is up and running. Otherwise, the old emulator is started in case of a emulator restart. This instruction should be used when a new emulator is introduced, or if a complete reboot of the system should be done.
relup(4), release_handler(3), supervisor(3), systools(3)