added gun connections holder genserver

This commit is contained in:
Alex S 2019-08-14 13:37:27 +03:00 committed by Ariadne Conill
parent 2469061657
commit aa0ab31b5b
5 changed files with 99 additions and 16 deletions

View File

@ -35,7 +35,8 @@ defmodule Pleroma.Application do
Pleroma.Emoji,
Pleroma.Captcha,
Pleroma.FlakeId,
Pleroma.ScheduledActivityWorker
Pleroma.ScheduledActivityWorker,
Pleroma.Gun.Connections
] ++
cachex_children() ++
hackney_pool_children() ++

View File

@ -26,8 +26,8 @@ defmodule Pleroma.Gun.Connections do
{:ok, %__MODULE__{conns: %{}}}
end
@spec get_conn(atom(), String.t(), keyword()) :: pid()
def get_conn(name \\ __MODULE__, url, opts \\ []) do
@spec get_conn(String.t(), keyword(), atom()) :: pid()
def get_conn(url, opts \\ [], name \\ __MODULE__) do
opts = Enum.into(opts, %{})
uri = URI.parse(url)
@ -39,6 +39,27 @@ defmodule Pleroma.Gun.Connections do
)
end
# TODO: only for testing, add this parameter to the config
@spec try_to_get_gun_conn(String.t(), keyword(), atom()) :: nil | pid()
def try_to_get_gun_conn(url, opts \\ [], name \\ __MODULE__),
do: try_to_get_gun_conn(url, opts, name, 0)
@spec try_to_get_gun_conn(String.t(), keyword(), atom(), pos_integer()) :: nil | pid()
def try_to_get_gun_conn(_url, _, _, 3), do: nil
def try_to_get_gun_conn(url, opts, name, acc) do
case Pleroma.Gun.Connections.get_conn(url, opts, name) do
nil -> try_to_get_gun_conn(url, acc + 1)
conn -> conn
end
end
@spec alive?(atom()) :: boolean()
def alive?(name \\ __MODULE__) do
pid = Process.whereis(name)
if pid, do: Process.alive?(pid), else: false
end
@spec get_state(atom()) :: t()
def get_state(name \\ __MODULE__) do
GenServer.call(name, {:state})

View File

@ -32,6 +32,15 @@ defmodule Pleroma.HTTP do
process_request_options(options)
|> process_sni_options(url)
adapter_gun? = Application.get_env(:tesla, :adapter) == Tesla.Adapter.Gun
options =
if adapter_gun? and Pleroma.Gun.Connections.alive?() do
get_conn_for_gun(url, options)
else
options
end
params = Keyword.get(options, :params, [])
%{}
@ -52,6 +61,20 @@ defmodule Pleroma.HTTP do
end
end
defp get_conn_for_gun(url, options) do
case Pleroma.Gun.Connections.try_to_get_gun_conn(url) do
nil ->
options
conn ->
adapter_opts =
Keyword.get(options, :adapter, [])
|> Keyword.put(:conn, conn)
Keyword.put(options, :adapter, adapter_opts)
end
end
defp process_sni_options(options, nil), do: options
defp process_sni_options(options, url) do

View File

@ -3,23 +3,56 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Gun.ConnectionsTest do
use ExUnit.Case, async: true
use ExUnit.Case
alias Pleroma.Gun.{Connections, Conn, API}
setup do
name = :test_gun_connections
adapter = Application.get_env(:tesla, :adapter)
Application.put_env(:tesla, :adapter, Tesla.Adapter.Gun)
on_exit(fn -> Application.put_env(:tesla, :adapter, adapter) end)
{:ok, pid} = Connections.start_link(name)
{:ok, name: name, pid: pid}
end
describe "alive?/2" do
test "is alive", %{name: name} do
assert Connections.alive?(name)
end
test "returns false if not started" do
refute Connections.alive?(:some_random_name)
end
end
test "try_to_get_gun_conn/1 returns conn", %{name: name, pid: pid} do
conn = Connections.try_to_get_gun_conn("http://some-domain.com", [genserver_pid: pid], name)
assert is_pid(conn)
assert Process.alive?(conn)
reused_conn = Connections.get_conn("http://some-domain.com", [genserver_pid: pid], name)
assert conn == reused_conn
%Connections{
conns: %{
"some-domain.com:80" => %Conn{
conn: ^conn,
state: :up,
waiting_pids: []
}
}
} = Connections.get_state(name)
end
test "opens connection and reuse it on next request", %{name: name, pid: pid} do
conn = Connections.get_conn(name, "http://some-domain.com", genserver_pid: pid)
conn = Connections.get_conn("http://some-domain.com", [genserver_pid: pid], name)
assert is_pid(conn)
assert Process.alive?(conn)
reused_conn = Connections.get_conn(name, "http://some-domain.com", genserver_pid: pid)
reused_conn = Connections.get_conn("http://some-domain.com", [genserver_pid: pid], name)
assert conn == reused_conn
@ -35,15 +68,15 @@ defmodule Gun.ConnectionsTest do
end
test "reuses connection based on protocol", %{name: name, pid: pid} do
conn = Connections.get_conn(name, "http://some-domain.com", genserver_pid: pid)
conn = Connections.get_conn("http://some-domain.com", [genserver_pid: pid], name)
assert is_pid(conn)
assert Process.alive?(conn)
https_conn = Connections.get_conn(name, "https://some-domain.com", genserver_pid: pid)
https_conn = Connections.get_conn("https://some-domain.com", [genserver_pid: pid], name)
refute conn == https_conn
reused_https = Connections.get_conn(name, "https://some-domain.com", genserver_pid: pid)
reused_https = Connections.get_conn("https://some-domain.com", [genserver_pid: pid], name)
refute conn == reused_https
@ -66,7 +99,7 @@ defmodule Gun.ConnectionsTest do
end
test "process gun_down message", %{name: name, pid: pid} do
conn = Connections.get_conn(name, "http://gun_down.com", genserver_pid: pid)
conn = Connections.get_conn("http://gun_down.com", [genserver_pid: pid], name)
refute conn
@ -82,7 +115,7 @@ defmodule Gun.ConnectionsTest do
end
test "process gun_down message and then gun_up", %{name: name, pid: pid} do
conn = Connections.get_conn(name, "http://gun_down_and_up.com", genserver_pid: pid)
conn = Connections.get_conn("http://gun_down_and_up.com", [genserver_pid: pid], name)
refute conn
@ -96,7 +129,7 @@ defmodule Gun.ConnectionsTest do
}
} = Connections.get_state(name)
conn = Connections.get_conn(name, "http://gun_down_and_up.com", genserver_pid: pid)
conn = Connections.get_conn("http://gun_down_and_up.com", [genserver_pid: pid], name)
assert is_pid(conn)
assert Process.alive?(conn)
@ -116,7 +149,7 @@ defmodule Gun.ConnectionsTest do
tasks =
for _ <- 1..5 do
Task.async(fn ->
Connections.get_conn(name, "http://some-domain.com", genserver_pid: pid)
Connections.get_conn("http://some-domain.com", [genserver_pid: pid], name)
end)
end
@ -149,12 +182,12 @@ defmodule Gun.ConnectionsTest do
api = Pleroma.Config.get([API])
Pleroma.Config.put([API], :gun)
on_exit(fn -> Pleroma.Config.put([API], api) end)
conn = Connections.get_conn(name, "http://httpbin.org")
conn = Connections.get_conn("http://httpbin.org", [], name)
assert is_pid(conn)
assert Process.alive?(conn)
reused_conn = Connections.get_conn(name, "http://httpbin.org")
reused_conn = Connections.get_conn("http://httpbin.org", [], name)
assert conn == reused_conn

View File

@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ReverseProxyTest do
use Pleroma.Web.ConnCase, async: true
use Pleroma.Web.ConnCase
import ExUnit.CaptureLog
import Mox
alias Pleroma.ReverseProxy
@ -322,6 +322,10 @@ defmodule Pleroma.ReverseProxyTest do
adapter = Application.get_env(:tesla, :adapter)
Application.put_env(:tesla, :adapter, Tesla.Adapter.Gun)
api = Pleroma.Config.get([Pleroma.Gun.API])
Pleroma.Config.put([Pleroma.Gun.API], :gun)
{:ok, _} = Pleroma.Gun.Connections.start_link(Pleroma.Gun.Connections)
conn = ReverseProxy.call(conn, "http://httpbin.org/stream-bytes/10")
assert byte_size(conn.resp_body) == 10
@ -331,6 +335,7 @@ defmodule Pleroma.ReverseProxyTest do
on_exit(fn ->
Pleroma.Config.put([Pleroma.ReverseProxy.Client], client)
Application.put_env(:tesla, :adapter, adapter)
Pleroma.Config.put([Pleroma.Gun.API], api)
end)
end
end