Current section
Files
Jump to
Current section
Files
lib/failover/failover.ex
defmodule Failover do
@moduledoc """
This module provides a GenServer that can be used to handle failover across
regions or dc's.
This module provides two callbacks to be handled by the calling service:
- handle_call(:failover_start, _from, state)
- handle_call(:failover_stop, _from, state)
:failover_start
This event will be sent when your service is required to start doing work.
That is, your instance will receive this event if:
- We are configured as the primary instance, in which case it will receive
this event ASAP.
- We are configured as a failover and we've noticed the primary is dead.
:failover_stop
This event will fire if this instance is doing work and one of these happen:
- Our zk session has expired
- We've lost our zk connection.
- You are a failover instance and we've detected the primary instance is up
In any of these cases, your service should stop doing work, else you risk
having both primary and failover instances doing work at the same time.
"""
require Logger
def start_link(instance_pid) do
barrier_path = Application.get_env(:db2kafka, :barrier_path)
primary_region = Application.get_env(:db2kafka, :primary_region)
region = Application.get_env(:db2kafka, :region)
if primary_region == region do
Logger.info("Starting as primary (in #{region})")
Failover.Primary.start_link(instance_pid, barrier_path)
else
Logger.info("Starting as secondary (in #{region})")
Failover.Secondary.start_link(instance_pid, barrier_path)
end
end
# Common functionality across all failover run modes
def init_state(instance_pid, barrier_path) do
{:ok, zk_barrier} = Failover.ZKBarrier.start_link(self())
initial_state = %{
zk_barrier: zk_barrier,
instance_pid: instance_pid,
instance_is_probably_doing_work: false,
barrier_path: barrier_path,
}
{:ok, initial_state}
end
def start_app(state) do
Logger.info("Starting app")
:ok = GenServer.call(state[:instance_pid], :failover_start)
{:ok, %{state | instance_is_probably_doing_work: true}}
end
def stop_app(state) do
if state[:instance_is_probably_doing_work] do
Logger.info("Stopping app")
:ok = GenServer.call(state[:instance_pid], :failover_stop)
end
{:ok, %{state | instance_is_probably_doing_work: false}}
end
end