Merge remote-tracking branch 'remotes/origin/develop' into feature/object-hashtags...
[akkoma] / lib / pleroma / gun / connection_pool / reclaimer.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Gun.ConnectionPool.Reclaimer do
6 use GenServer, restart: :temporary
7
8 @registry Pleroma.Gun.ConnectionPool
9
10 def start_monitor do
11 pid =
12 case :gen_server.start(__MODULE__, [], name: {:via, Registry, {@registry, "reclaimer"}}) do
13 {:ok, pid} ->
14 pid
15
16 {:error, {:already_registered, pid}} ->
17 pid
18 end
19
20 {pid, Process.monitor(pid)}
21 end
22
23 @impl true
24 def init(_) do
25 {:ok, nil, {:continue, :reclaim}}
26 end
27
28 @impl true
29 def handle_continue(:reclaim, _) do
30 max_connections = Pleroma.Config.get([:connections_pool, :max_connections])
31
32 reclaim_max =
33 [:connections_pool, :reclaim_multiplier]
34 |> Pleroma.Config.get()
35 |> Kernel.*(max_connections)
36 |> round
37 |> max(1)
38
39 :telemetry.execute([:pleroma, :connection_pool, :reclaim, :start], %{}, %{
40 max_connections: max_connections,
41 reclaim_max: reclaim_max
42 })
43
44 # :ets.fun2ms(
45 # fn {_, {worker_pid, {_, used_by, crf, last_reference}}} when used_by == [] ->
46 # {worker_pid, crf, last_reference} end)
47 unused_conns =
48 Registry.select(
49 @registry,
50 [
51 {{:_, :"$1", {:_, :"$2", :"$3", :"$4"}}, [{:==, :"$2", []}], [{{:"$1", :"$3", :"$4"}}]}
52 ]
53 )
54
55 case unused_conns do
56 [] ->
57 :telemetry.execute(
58 [:pleroma, :connection_pool, :reclaim, :stop],
59 %{reclaimed_count: 0},
60 %{
61 max_connections: max_connections
62 }
63 )
64
65 {:stop, :no_unused_conns, nil}
66
67 unused_conns ->
68 reclaimed =
69 unused_conns
70 |> Enum.sort(fn {_pid1, crf1, last_reference1}, {_pid2, crf2, last_reference2} ->
71 crf1 <= crf2 and last_reference1 <= last_reference2
72 end)
73 |> Enum.take(reclaim_max)
74
75 reclaimed
76 |> Enum.each(fn {pid, _, _} ->
77 DynamicSupervisor.terminate_child(Pleroma.Gun.ConnectionPool.WorkerSupervisor, pid)
78 end)
79
80 :telemetry.execute(
81 [:pleroma, :connection_pool, :reclaim, :stop],
82 %{reclaimed_count: Enum.count(reclaimed)},
83 %{max_connections: max_connections}
84 )
85
86 {:stop, :normal, nil}
87 end
88 end
89 end