Goodoo (Goodoo v0.1.0) View Source

Goodoo is a simple, robust, and highly customizable health check solution written in Elixir.

Goodoo works by periodically checking the availablity of the sub-systems based on your configuration, and provides a few APIs to retrieves the report.

To start using Goodoo, create a module:

defmodule MyHealthCheck do
  use Goodoo
end

After that, add the module with the desired checkers to the supervisor tree. Please see the "Checkers" section for all currently supported checkers.

checkers = %{
  "primary" => {Goodoo.Checker.EctoSQL, repo: MyPrimaryRepo},
  "replica" => {Goodoo.Checker.EctoSQL, repo: MyReplicaRepo},
  "persistent_cache" => {Goodoo.Checker.Redix, connection: MyCache}
}

children = [
  MyPrimaryRepo,
  MyReplicaRepo,
  MyCache,
  ...,
  {MyHealthCheck, checkers},
  MyEndpoint
]

Supervisor.start_link(children, strategy: :one_for_one, name: MyApp)

Allez, hop! You are "goodoo" to go. To retrieve the health check report, list_health_states/1 and get_health_state/2 can be used.

Usually you might want to expose an HTTP endpoint for some uptime checkers e.g. AWS ALB, Pingdom, etc. It can be easily done with Plug.

defmodule MyRouter do
  use Plug.Router

  plug :match
  plug :dispatch

  get "/health" do
    healthy? =
      Enum.all?(
        Goodoo.list_health_states(MyHealthCheck),
        fn {_checker_name, {state, _last_checked_at}} ->
          state == :healthy
        end
      )

    if healthy? do
      send_resp(conn, 200, "Everything is 200 OK")
    else
      send_resp(conn, 503, "Something is on fire!")
    end
  end

  get "/health/:checker_name" do
    case Goodoo.get_health_state(MyHealthCheck, checker_name) do
      nil ->
        send_resp(conn, 404, "Not found")

      {state, _last_checked_at} ->
        if state == :healthy do
          send_resp(conn, 200, "Service is doing fine")
        else
          send_resp(conn, 503, "Service is on fire")
        end
    end
  end
end

Checkers

Goodoo implemented a few common checkers:

For more information, please visit the documentation for them accordingly.

Goodoo supports customer checkers, please visit Goodoo.Checker for more information.

Checker scheduling/interval

Goodoo schedules checkers based on the last health state. The default intervals are:

  • :healthy - next check will be in 30 seconds.
  • :degraded - next check will be in 10 seconds.
  • :unhealthy - next check will be in 3 seconds.

You can configure your own strategy with the following example. Please note that missing intervals will fall back to the defaults.

# `:healthy` and `:degraded` will fall back to defaults.
repo_intervals = %{
  unhealthy: 1_000
}

cache_intervals = %{
  unhealthy: 1_000,
  degraded: 5_000,
  healthy: 15_000
}

checkers = %{
  "repo" => {Goodoo.Checker.EctoSQL, repo: MyRepo, intervals: repo_intervals},
  "cache" => {Goodoo.Checker.EctoSQL, connection: MyCache, intervals: cache_intervals}
}

Link to this section Summary

Functions

Retrieve the checker status by its name of a healthcheck module

Retrieves all checker statuses of a healthcheck module.

Link to this section Functions

Link to this function

get_health_state(module, name)

View Source

Specs

get_health_state(module(), Goodoo.Checker.name()) ::
  {Goodoo.Checker.health_state(), DateTime.t()} | nil

Retrieve the checker status by its name of a healthcheck module

Link to this function

list_health_states(module)

View Source

Specs

list_health_states(module()) :: %{
  required(Goodoo.Checker.name()) =>
    {Goodoo.Checker.health_state(), DateTime.t()}
}

Retrieves all checker statuses of a healthcheck module.