Packages
tesla
1.20.0
1.20.0
1.18.3
1.18.2
1.18.1
1.18.0
1.17.0
1.16.0
1.15.3
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.1
1.14.0
1.13.2
1.13.1
1.13.0
1.12.3
1.12.2
1.12.1
1.12.0
1.11.2
1.11.1
1.11.0
1.10.3
1.10.2
1.10.1
1.10.0
1.9.0
1.8.1
retired
1.8.0
1.7.0
1.6.1
1.6.0
1.5.1
1.5.0
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.3
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.0
1.0.0
1.0.0-beta.1
0.10.0
0.9.0
0.8.0
0.7.2
0.7.1
0.7.0
0.6.0
0.5.2
0.5.1
0.5.0
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.2.2
0.2.1
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
HTTP client library, with support for middleware and multiple adapters.
Current section
Files
Jump to
Current section
Files
lib/tesla/middleware/timeout.ex
defmodule Tesla.Middleware.Timeout do
@moduledoc """
Timeout HTTP request after X milliseconds.
## Examples
```elixir
defmodule MyClient do
def client do
Tesla.client([
{Tesla.Middleware.Timeout, timeout: 2_000}
])
end
end
```
If you are using OpenTelemetry in your project, you may be interested in
using `OpentelemetryProcessPropagator.Task` to have a better integration using
the `task_module` option.
```elixir
defmodule MyClient do
def client do
Tesla.client([
{Tesla.Middleware.Timeout, [
timeout: 2_000,
task_module: OpentelemetryProcessPropagator.Task
}
])
end
end
```
## Options
- `:timeout` - number of milliseconds a request is allowed to take (defaults to `1000`)
- `:task_module` - the `Task` module used to spawn tasks. Useful when you want
to use alternatives such as `OpentelemetryProcessPropagator.Task` from the OTEL
project.
"""
@behaviour Tesla.Middleware
@default_timeout 1_000
@impl Tesla.Middleware
def call(env, next, opts) do
opts = opts || []
timeout = Keyword.get(opts, :timeout, @default_timeout)
task_module = Keyword.get(opts, :task_module, Task)
env = put_gun_stream_owner(env, self())
task = safe_async(task_module, fn -> Tesla.run(env, next) end)
try do
task
|> task_module.await(timeout)
|> repass_error
catch
:exit, {:timeout, _} ->
task_module.shutdown(task, 0)
{:error, :timeout}
end
end
defp safe_async(task_module, func) do
task_module.async(fn ->
try do
{:ok, func.()}
rescue
e in _ ->
{:exception, e, __STACKTRACE__}
catch
type, value ->
{type, value}
end
end)
end
defp put_gun_stream_owner(env, stream_owner),
do: %{env | private: Map.put_new(env.private, :tesla_gun_stream_owner, stream_owner)}
defp repass_error({:exception, error, stacktrace}), do: reraise(error, stacktrace)
defp repass_error({:throw, value}), do: throw(value)
defp repass_error({:exit, value}), do: exit(value)
defp repass_error({:ok, result}), do: result
end