pgsql: move logic out of watcher, wire mode of operation

This commit is contained in:
Timothée Floure 2022-02-21 10:42:55 +01:00
parent 9ddd999ed8
commit c33ffd5139
Signed by: tfloure
GPG key ID: 4502C902C00A1E12
5 changed files with 54 additions and 22 deletions

View file

@ -1,10 +1,45 @@
defmodule HAHandler.PGSQL do defmodule HAHandler.PGSQL do
@supervisor HAHandler.PGSQL.Supervisor @supervisor HAHandler.PGSQL.Supervisor
@version_query "SELECT version();"
@is_in_recovery_query "SELECT pg_is_in_recovery();"
def status() do def get_instances() do
watchers = Supervisor.which_children(@supervisor) watchers = Supervisor.which_children(@supervisor)
for {_id, pid, _type, _modules} <- watchers do for {hostname, pid, _type, _modules} <- watchers do
GenServer.call(pid, :status) {hostname, pid}
end end
end end
def get_version({hostname, pid}) do
case GenServer.call(pid, {:execute, @version_query, []}) do
{:ok, %Postgrex.Result{rows: [[raw_version_string]]}} ->
version = case Regex.run(~r/^PostgreSQL (\d+\.\d+)/, raw_version_string) do
[_, version_number] -> version_number
_ -> "unknown"
end
%{hostname: hostname, version: version, status: "up"}
{:error, %DBConnection.ConnectionError{message: _msg, reason: err}} ->
%{hostname: hostname, version: "unknown", status: err}
_ ->
%{hostname: hostname, version: "unknown", status: :unknown}
end
end
def get_operation_mode({_hostname, pid}) do
case GenServer.call(pid, {:execute, @is_in_recovery_query, []}) do
{:ok, %Postgrex.Result{rows: [[false]]}} ->
:primary
{:ok, %Postgrex.Result{rows: [[true]]}} ->
:secondary
_ ->
:unknown
end
end
def get_stats() do
get_instances()
|> Enum.map(fn instance ->
get_version(instance) |> Map.put(:mode, get_operation_mode(instance))
end)
end
end end

View file

@ -9,7 +9,12 @@ defmodule HAHandler.PGSQL.Supervisor do
@impl true @impl true
def init(instances) do def init(instances) do
children = Enum.map(instances, fn conf -> {PGSQLWatcher, conf} end) children = Enum.map(instances, fn conf ->
%{
id: Keyword.get(conf, :hostname),
start: {PGSQLWatcher, :start_link, [conf]}
}
end)
opts = [ strategy: :one_for_one ] opts = [ strategy: :one_for_one ]
Supervisor.init(children, opts) Supervisor.init(children, opts)

View file

@ -3,7 +3,7 @@ defmodule HAHandler.PGSQL.Watcher do
require Logger require Logger
def start_link(opts) do def start_link(opts) do
GenServer.start_link(__MODULE__, opts, name: __MODULE__) GenServer.start_link(__MODULE__, opts)
end end
@impl true @impl true
@ -23,20 +23,7 @@ defmodule HAHandler.PGSQL.Watcher do
end end
@impl true @impl true
def handle_call(:status, _from, %{backend: backend, hostname: hostname} = state) do def handle_call({:execute, query, params}, _from, %{backend: backend} = state) do
result = case Postgrex.query(backend, "SELECT version();", []) do {:reply, Postgrex.query(backend, query, params), state}
{:ok, %Postgrex.Result{rows: [[raw_version_string]]}} ->
version = case Regex.run(~r/^PostgreSQL (\d+\.\d+)/, raw_version_string) do
[_, version_number] -> version_number
_ -> "unknown"
end
%{hostname: hostname, version: version, status: "up"}
{:error, %DBConnection.ConnectionError{message: _msg, reason: err}} ->
%{hostname: hostname, version: "unknown", status: err}
_ ->
%{hostname: hostname, version: "unknown", status: "Unhandled error"}
end
{:reply, result, state}
end end
end end

View file

@ -19,9 +19,12 @@ defmodule HAHandler.Web.Controller do
def index(conn) do def index(conn) do
{:ok, hostname} = :net_adm.dns_hostname(:net_adm.localhost) {:ok, hostname} = :net_adm.dns_hostname(:net_adm.localhost)
haproxy_stats = HAProxy.get_stats([hide_error: true])
pgsql_stats = PGSQL.get_stats()
assigns = [ assigns = [
haproxy_stats: HAProxy.get_stats([hide_error: true]), haproxy_stats: haproxy_stats,
pgsql_status: PGSQL.status(), pgsql_status: pgsql_stats,
hostname: hostname, hostname: hostname,
otp_app: HAHandler.otp_app(), otp_app: HAHandler.otp_app(),
version: HAHandler.version(), version: HAHandler.version(),

View file

@ -109,6 +109,7 @@
<th>Hostname</th> <th>Hostname</th>
<th>Version</th> <th>Version</th>
<th>Status</th> <th>Status</th>
<th>Operation</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -117,6 +118,7 @@
<td><%= entry[:hostname] %></td> <td><%= entry[:hostname] %></td>
<td><%= entry[:version] %></td> <td><%= entry[:version] %></td>
<td><%= entry[:status] %></td> <td><%= entry[:status] %></td>
<td><%= entry[:mode] %></td>
</tr> </tr>
<% end %> <% end %>
</tbody> </tbody>