Blue-green release swaps and in-process hot upgrades for a single Elixir node.
BeamDeploy keeps a long-lived parent node running locally and serves traffic
from a child peer node started with OTP's :peer module. When you hand the
parent a new mix release tarball, it boots a new peer with the new release,
lets both peers overlap on the same socket via SO_REUSEPORT, then gracefully
shuts down the old one.
The package is intentionally small:
- no storage, polling, or orchestration layer
- no Docker or platform coupling
- local tarball input only
You copy a release tarball onto the host and call either:
BeamDeploy.upgrade/1for a blue-green peer swapBeamDeploy.hot_upgrade/2for an in-process hot code reload
Integration
defmodule MyApp.Application do
use Application
def start(type, args) do
BeamDeploy.start_link(
otp_app: :my_app,
start: {__MODULE__, :start_app, [type, args]},
endpoint: MyAppWeb.Endpoint
)
end
def start_app(_type, _args) do
children = [MyApp.Repo, MyAppWeb.Endpoint]
Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)
end
endEnable parent/peer mode in production with either:
config :beam_deploy, enabled: trueor:
BEAM_DEPLOY=trueIn environments where BeamDeploy is not enabled, start_link/1 and
start_link/2 just call your start_app MFA directly.
Upgrades
BeamDeploy.upgrade("/tmp/my_app-0.2.0.tar.gz")
# => :ok
BeamDeploy.hot_upgrade("/tmp/my_app-0.2.0.tar.gz", otp_app: :my_app)
# => :okThe tarball must be a standard mix release archive built with the same OTP
version as the running node.
Hot upgrades are only safe for compatible code changes. Use a cold deploy or the blue-green path instead when changing supervision tree shape, upgrading Erlang/OTP, changing major runtime topology, or touching NIFs.
Summary
Functions
Returns true when BeamDeploy parent/peer mode is enabled for this runtime.
Returns all handoff data as a map.
Reads handoff data from the parent node.
Performs an in-process hot upgrade from a local release tarball path.
Returns the incoming replacement peer for the current peer, if one exists.
Returns the outgoing peer being replaced by the current peer, if one exists.
Returns the active peer node, or nil when BeamDeploy is not running.
Stores handoff data that survives peer transitions.
Starts BeamDeploy without parent-level children.
Starts BeamDeploy with optional parent-level children.
Returns the current blue-green status map.
Performs a blue-green upgrade from a local release tarball path.
Returns true if a release swap is currently running.
Functions
@spec enabled?() :: boolean()
Returns true when BeamDeploy parent/peer mode is enabled for this runtime.
@spec get_all_handoff() :: map()
Returns all handoff data as a map.
Reads handoff data from the parent node.
Performs an in-process hot upgrade from a local release tarball path.
This path does not depend on the parent/peer runtime. It reloads code inside
the current node, suspends affected processes, runs code_change/3, and
resumes them.
Supported changes are limited to compatible hot-code updates built with the same Erlang/OTP version. NIF upgrades are skipped.
@spec incoming_peer() :: node() | nil
Returns the incoming replacement peer for the current peer, if one exists.
@spec outgoing_peer() :: node() | nil
Returns the outgoing peer being replaced by the current peer, if one exists.
@spec peer_node() :: node() | nil
Returns the active peer node, or nil when BeamDeploy is not running.
Stores handoff data that survives peer transitions.
@spec start_link(keyword()) :: Supervisor.on_start()
Starts BeamDeploy without parent-level children.
@spec start_link( [Supervisor.child_spec()], keyword() ) :: Supervisor.on_start()
Starts BeamDeploy with optional parent-level children.
Parent children run on the long-lived parent node before the peer manager. This is useful for services that should not restart on every cutover.
Returns the current blue-green status map.
Performs a blue-green upgrade from a local release tarball path.
The call can be made from either the parent or active peer node.
@spec upgrading?() :: boolean()
Returns true if a release swap is currently running.