diff --git a/lib/grpc/client/adapters/mint.ex b/lib/grpc/client/adapters/mint.ex index e361e0dd..d82ad2d1 100644 --- a/lib/grpc/client/adapters/mint.ex +++ b/lib/grpc/client/adapters/mint.ex @@ -1,6 +1,6 @@ defmodule GRPC.Client.Adapters.Mint do @moduledoc """ - A client adapter using mint + A client adapter using Mint. """ alias GRPC.Channel @@ -10,9 +10,25 @@ defmodule GRPC.Client.Adapters.Mint do @behaviour GRPC.Client.Adapter - @default_connect_opts [protocols: [:http2]] + @default_connect_opts [ + protocols: [:http2] + ] + @default_client_settings [ + initial_window_size: 8_000_000, + max_frame_size: 8_000_000 + ] @default_transport_opts [timeout: :infinity] + @doc """ + Connects using Mint based on the provided configs. Options + * `:transport_opts`: Defaults to `[timeout: :infinity]`, given the nature of H2 connections (with support to + long-lived streams) this default is set to avoid timeouts while waiting for server streams to complete. The other + options may vary based on the transport used for this connection (tcp or ssl). Check [Mint.HTTP.connect/4](https://hexdocs.pm/mint/Mint.HTTP.html#connect/4) + * `:client_settings`: Defaults to `[initial_window_size: 8_000_000, max_frame_size: 8_000_000]`, a larger default + window size ensures that the number of packages exchanges is smaller, thus speeding up the requests by reducing the + amount of networks round trip, with the cost of having larger packages reaching the server per connection. + Check [Mint.HTTP2.setting() type](https://hexdocs.pm/mint/Mint.HTTP2.html#t:setting/0) for additional configs. + """ @impl true def connect(%{host: host, port: port} = channel, opts \\ []) do # Added :config_options to facilitate testing. @@ -119,12 +135,22 @@ defmodule GRPC.Client.Adapters.Mint do |> Keyword.get(:transport_opts, []) |> Keyword.merge(ssl) - [transport_opts: Keyword.merge(@default_transport_opts, transport_opts)] + client_settings = Keyword.get(opts, :client_settings, @default_client_settings) + + [ + transport_opts: Keyword.merge(@default_transport_opts, transport_opts), + client_settings: client_settings + ] end defp connect_opts(_channel, opts) do transport_opts = Keyword.get(opts, :transport_opts, []) - [transport_opts: Keyword.merge(@default_transport_opts, transport_opts)] + client_settings = Keyword.get(opts, :client_settings, @default_client_settings) + + [ + transport_opts: Keyword.merge(@default_transport_opts, transport_opts), + client_settings: client_settings + ] end defp merge_opts(opts, module_opts) do diff --git a/test/grpc/client/adapters/mint_test.exs b/test/grpc/client/adapters/mint_test.exs index b3f8d12d..261235fd 100644 --- a/test/grpc/client/adapters/mint_test.exs +++ b/test/grpc/client/adapters/mint_test.exs @@ -47,5 +47,36 @@ defmodule GRPC.Client.Adapters.MintTest do assert message == "Error while opening connection: {:error, :badarg}" end + + test "defaults client settings when none is passed", %{port: port} do + channel = build(:channel, adapter: Mint, port: port, host: "localhost") + + assert {:ok, result} = Mint.connect(channel, []) + # wait for settings to be pushed + Process.sleep(50) + state = :sys.get_state(result.adapter_payload.conn_pid) + + assert %{initial_window_size: 8_000_000, max_frame_size: 8_000_000} = + Map.get(state.conn, :client_settings) + end + + test "allow client settings to be passed", %{port: port} do + channel = build(:channel, adapter: Mint, port: port, host: "localhost") + + assert {:ok, result} = + Mint.connect(channel, + client_settings: [ + initial_window_size: 50_000, + max_frame_size: 50_000 + ] + ) + + # wait for settings to be pushed + Process.sleep(50) + state = :sys.get_state(result.adapter_payload.conn_pid) + + assert %{initial_window_size: 50_000, max_frame_size: 50_000} = + Map.get(state.conn, :client_settings) + end end end