Merge remote-tracking branch 'remotes/origin/develop' into automatic-authentication...
[akkoma] / lib / pleroma / healthcheck.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Healthcheck do
6 @moduledoc """
7 Module collects metrics about app and assign healthy status.
8 """
9 alias Pleroma.Healthcheck
10 alias Pleroma.Repo
11
12 @derive Jason.Encoder
13 defstruct pool_size: 0,
14 active: 0,
15 idle: 0,
16 memory_used: 0,
17 job_queue_stats: nil,
18 healthy: true
19
20 @type t :: %__MODULE__{
21 pool_size: non_neg_integer(),
22 active: non_neg_integer(),
23 idle: non_neg_integer(),
24 memory_used: number(),
25 job_queue_stats: map(),
26 healthy: boolean()
27 }
28
29 @spec system_info() :: t()
30 def system_info do
31 %Healthcheck{
32 memory_used: Float.round(:erlang.memory(:total) / 1024 / 1024, 2)
33 }
34 |> assign_db_info()
35 |> assign_job_queue_stats()
36 |> check_health()
37 end
38
39 defp assign_db_info(healthcheck) do
40 database = Pleroma.Config.get([Repo, :database])
41
42 query =
43 "select state, count(pid) from pg_stat_activity where datname = '#{database}' group by state;"
44
45 result = Repo.query!(query)
46 pool_size = Pleroma.Config.get([Repo, :pool_size])
47
48 db_info =
49 Enum.reduce(result.rows, %{active: 0, idle: 0}, fn [state, cnt], states ->
50 if state == "active" do
51 Map.put(states, :active, states.active + cnt)
52 else
53 Map.put(states, :idle, states.idle + cnt)
54 end
55 end)
56 |> Map.put(:pool_size, pool_size)
57
58 Map.merge(healthcheck, db_info)
59 end
60
61 defp assign_job_queue_stats(healthcheck) do
62 stats = Pleroma.JobQueueMonitor.stats()
63 Map.put(healthcheck, :job_queue_stats, stats)
64 end
65
66 @spec check_health(Healthcheck.t()) :: Healthcheck.t()
67 def check_health(%{pool_size: pool_size, active: active} = check)
68 when active >= pool_size do
69 %{check | healthy: false}
70 end
71
72 def check_health(check), do: check
73 end