diff --git a/lib/hardhat/builder.ex b/lib/hardhat/builder.ex index 1f5cdf4..14c3f74 100644 --- a/lib/hardhat/builder.ex +++ b/lib/hardhat/builder.ex @@ -8,6 +8,8 @@ defmodule Hardhat.Builder do invalid -> raise "Invalid strategy #{inspect(invalid)}" end + opts = opts |> Keyword.delete(:strategy) |> Keyword.put_new(:docs, false) + client_mod = __CALLER__.module regulator_name = Module.concat(client_mod, Regulator) @@ -20,7 +22,6 @@ defmodule Hardhat.Builder do quote location: :keep do @before_compile Hardhat.Builder - # docs: false use Tesla.Builder, unquote(opts) @strategy unquote(strategy) @@ -28,6 +29,7 @@ defmodule Hardhat.Builder do adapter(Tesla.Adapter.Finch, name: __MODULE__) defmodule Sup do + @moduledoc false use Supervisor def start_link(init_arg) do @@ -45,14 +47,20 @@ defmodule Hardhat.Builder do end end + @doc false def child_spec(opts) do Supervisor.child_spec(__MODULE__.Sup, opts) end + @doc false defdelegate pool_options(overrides), to: Hardhat.Defaults + @doc false defdelegate should_melt(env), to: Hardhat.Defaults + @doc false defdelegate deadline_propagation_opts(), to: Hardhat.Defaults + @doc false defdelegate should_retry(result), to: Hardhat.Defaults + @doc false defdelegate should_regulate(result), to: Hardhat.Defaults @doc false diff --git a/lib/hardhat/middleware/deadline_propagation.ex b/lib/hardhat/middleware/deadline_propagation.ex index c50fa8a..7d1139c 100644 --- a/lib/hardhat/middleware/deadline_propagation.ex +++ b/lib/hardhat/middleware/deadline_propagation.ex @@ -1,7 +1,9 @@ defmodule Hardhat.Middleware.DeadlinePropagation do @moduledoc """ - Propagates `Deadline` information across the request to the - server being called. + Propagates `Deadline` information to the server being called via + an HTTP header. _This middleware is part of the default stack_. + + Expects a `:header` option, which defaults to `"deadline"`. See `Hardhat.Defaults.deadline_propagation_opts/0`. """ @behaviour Tesla.Middleware diff --git a/lib/hardhat/middleware/path_params.ex b/lib/hardhat/middleware/path_params.ex index f11930b..28323b7 100644 --- a/lib/hardhat/middleware/path_params.ex +++ b/lib/hardhat/middleware/path_params.ex @@ -1,7 +1,8 @@ defmodule Hardhat.Middleware.PathParams do @moduledoc """ Use templated URLs with separate params. Unlike `Tesla.Middleware.PathParams`, - we ensure that all parameters are URL-safe. + we ensure that all parameters are URL-safe. _This middleware is part of the + default stack_. """ @behaviour Tesla.Middleware diff --git a/lib/hardhat/middleware/regulator.ex b/lib/hardhat/middleware/regulator.ex index 8a2957a..2e528ca 100644 --- a/lib/hardhat/middleware/regulator.ex +++ b/lib/hardhat/middleware/regulator.ex @@ -1,4 +1,15 @@ defmodule Hardhat.Middleware.Regulator do + @moduledoc """ + Limits concurrent requests to the server based on a [loss based dynamic limit algorithm](`Regulator.Limit.AIMD`). + Additively increases the concurrency limit when there are no errors and multiplicatively + decrements the limit when there are errors. + + _This middleware is part of the default stack when giving the `strategy: :regulator` option to `use Hardhat`._ + + See also: + - Configuration options: `Hardhat.Defaults.regulator_opts/1` + - Determining what amounts to an error: `Hardhat.Defaults.should_regulate/1` + """ @behaviour Tesla.Middleware @impl Tesla.Middleware diff --git a/lib/hardhat/middleware/timeout.ex b/lib/hardhat/middleware/timeout.ex index ce8e7e9..68630ba 100644 --- a/lib/hardhat/middleware/timeout.ex +++ b/lib/hardhat/middleware/timeout.ex @@ -1,13 +1,30 @@ defmodule Hardhat.Middleware.Timeout do - @doc """ - Timeout HTTP request after X milliseconds. - - Includes: - - automatic propagation of OpenTelemetry tracing context - - addition of OpenTelemetry span events when the timeout is exceeded + @moduledoc """ + Abort HTTP requests after the given timeout or the current `Deadline`, + and emit `OpenTelemetry` trace events on timeouts. Options: - `:timeout` - (required) timeout in milliseconds + + ## OpenTelemetry + + Implementing a timeout necessitates moving the request into a new process, + and then waiting on that new process's completion (or aborting after the timeout). + Since `OpenTelemetry` tracing context is stored in the process dictionary, that + context must be explicitly propagated to the new process. This middleware uses + `OpentelemetryProcessPropagator` for this purpose. + + In the event of a timeout result in this middleware, a new `timeout_exceeded` event + will be added to the trace. The event will include these attributes: + + - `module` - the client module that includes this middleware + - `timeout` - the duration that was exceeded + + ## Deadline + + When the caller has set a `Deadline` for the current process, that limit will be + respected by this middleware. The effective timeout chosen will be the **lesser** of the time + remaining on the current deadline and the duration given in the `:timeout` option. """ alias OpentelemetryProcessPropagator.Task diff --git a/mix.exs b/mix.exs index dfc29b6..cdfe249 100644 --- a/mix.exs +++ b/mix.exs @@ -9,7 +9,8 @@ defmodule Hardhat.MixProject do start_permanent: Mix.env() == :prod, deps: deps(), description: "An opinionated, production-ready HTTP client for Elixir services.", - package: package() + package: package(), + docs: docs() ] end @@ -30,8 +31,8 @@ defmodule Hardhat.MixProject do {:fuse, "~> 2.5"}, {:regulator, "~> 0.5.0"}, {:deadline, "~> 0.7.1"}, - # {:recon, "~> 2.5.3", only: :test}, - {:ex_doc, ">= 0.0.0", only: :dev, runtime: false}, + # NOTE: Upgrade ex_doc past 0.30.6 when they fix the broken CSS + {:ex_doc, "0.30.5", only: :dev, runtime: false}, {:dialyxir, "~> 1.4.0", only: :dev}, {:bypass, "~> 2.1.0", only: :test} ] @@ -45,4 +46,10 @@ defmodule Hardhat.MixProject do } ] end + + defp docs do + [ + main: "Hardhat" + ] + end end diff --git a/mix.lock b/mix.lock index 25ddc1a..4762557 100644 --- a/mix.lock +++ b/mix.lock @@ -6,9 +6,9 @@ "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"}, "deadline": {:hex, :deadline, "0.7.1", "c34bd6b88be2f6ac6cf425a8e638a6f104c0117a60dc0dea9dff097ec27dcf07", [:mix], [], "hexpm", "3ba0f8173dd119c417f89b24207bd68b10f4e8b7bf9f6f20501f8901a3554801"}, "dialyxir": {:hex, :dialyxir, "1.4.1", "a22ed1e7bd3a3e3f197b68d806ef66acb61ee8f57b3ac85fc5d57354c5482a93", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "84b795d6d7796297cca5a3118444b80c7d94f7ce247d49886e7c291e1ae49801"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.33", "3c3fd9673bb5dcc9edc28dd90f50c87ce506d1f71b70e3de69aa8154bc695d44", [:mix], [], "hexpm", "2d526833729b59b9fdb85785078697c72ac5e5066350663e5be6a1182da61b8f"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.35", "437773ca9384edf69830e26e9e7b2e0d22d2596c4a6b17094a3b29f01ea65bb8", [:mix], [], "hexpm", "8652ba3cb85608d0d7aa2d21b45c6fad4ddc9a1f9a1f1b30ca3a246f0acc33f6"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "ex_doc": {:hex, :ex_doc, "0.30.6", "5f8b54854b240a2b55c9734c4b1d0dd7bdd41f71a095d42a70445c03cf05a281", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "bd48f2ddacf4e482c727f9293d9498e0881597eae6ddc3d9562bd7923375109f"}, + "ex_doc": {:hex, :ex_doc, "0.30.5", "aa6da96a5c23389d7dc7c381eba862710e108cee9cfdc629b7ec021313900e9e", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "88a1e115dcb91cefeef7e22df4a6ebbe4634fbf98b38adcbc25c9607d6d9d8e6"}, "finch": {:hex, :finch, "0.16.0", "40733f02c89f94a112518071c0a91fe86069560f5dbdb39f9150042f44dcfb1a", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f660174c4d519e5fec629016054d60edd822cdfe2b7270836739ac2f97735ec5"}, "fuse": {:hex, :fuse, "2.5.0", "71afa90be21da4e64f94abba9d36472faa2d799c67fedc3bd1752a88ea4c4753", [:rebar3], [], "hexpm", "7f52a1c84571731ad3c91d569e03131cc220ebaa7e2a11034405f0bac46a4fef"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},