Skip to content

Commit

Permalink
Merge pull request #568 from carrascoacd/acc/add-context-propagation
Browse files Browse the repository at this point in the history
OTel - Add context propagation
  • Loading branch information
yordis authored Apr 2, 2023
2 parents 958f856 + 077bfd3 commit 04a94e6
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 13 deletions.
36 changes: 25 additions & 11 deletions lib/tesla/middleware/timeout.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,30 @@ defmodule Tesla.Middleware.Timeout do
## Examples
```
defmodule MyClient do
use Tesla
defmodule MyClient do
use Tesla
plug Tesla.Middleware.Timeout, timeout: 2_000
end
```
plug Tesla.Middleware.Timeout, timeout: 2_000
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.
defmodule MyClient do
use Tesla
plug Tesla.Middleware.Timeout,
timeout: 2_000,
task_module: OpentelemetryProcessPropagator.Task
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
use alternatives such as `OpentelemetryProcessPropagator.Task` from OTEL
project.
"""

@behaviour Tesla.Middleware
Expand All @@ -25,22 +38,23 @@ defmodule Tesla.Middleware.Timeout do
def call(env, next, opts) do
opts = opts || []
timeout = Keyword.get(opts, :timeout, @default_timeout)
task_module = Keyword.get(opts, :task_module, Task)

task = safe_async(fn -> Tesla.run(env, next) end)
task = safe_async(task_module, fn -> Tesla.run(env, next) end)

try do
task
|> Task.await(timeout)
|> task_module.await(timeout)
|> repass_error
catch
:exit, {:timeout, _} ->
Task.shutdown(task, 0)
task_module.shutdown(task, 0)
{:error, :timeout}
end
end

defp safe_async(func) do
Task.async(fn ->
defp safe_async(task_module, func) do
task_module.async(fn ->
try do
{:ok, func.()}
rescue
Expand Down
3 changes: 2 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule Tesla.Mixfile do
use Mix.Project

@source_url "https://github.com/teamon/tesla"
@version "1.5.1"
@version "1.6.0"

def project do
[
Expand Down Expand Up @@ -75,6 +75,7 @@ defmodule Tesla.Mixfile do
{:telemetry, "~> 0.4 or ~> 1.0", optional: true},

# testing & docs
{:opentelemetry_process_propagator, "~> 0.1", only: [:test, :dev]},
{:excoveralls, "~> 0.8", only: :test},
{:httparrot, "~> 1.3", only: :test},
{:ex_doc, "~> 0.21", only: :dev, runtime: false},
Expand Down
3 changes: 3 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
"nimble_options": {:hex, :nimble_options, "0.4.0", "c89babbab52221a24b8d1ff9e7d838be70f0d871be823165c94dd3418eea728f", [:mix], [], "hexpm", "e6701c1af326a11eea9634a3b1c62b475339ace9456c1a23ec3bc9a847bca02d"},
"nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"},
"nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
"opentelemetry_api": {:hex, :opentelemetry_api, "1.2.1", "7b69ed4f40025c005de0b74fce8c0549625d59cb4df12d15c32fe6dc5076ff42", [:mix, :rebar3], [{:opentelemetry_semantic_conventions, "~> 0.2", [hex: :opentelemetry_semantic_conventions, repo: "hexpm", optional: false]}], "hexpm", "6d7a27b7cad2ad69a09cabf6670514cafcec717c8441beb5c96322bac3d05350"},
"opentelemetry_process_propagator": {:hex, :opentelemetry_process_propagator, "0.2.2", "85244a49f0c32ae1e2f3d58c477c265bd6125ee3480ade82b0fa9324b85ed3f0", [:mix, :rebar3], [{:opentelemetry_api, "~> 1.0", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}], "hexpm", "04db13302a34bea8350a13ed9d49c22dfd32c4bc590d8aa88b6b4b7e4f346c61"},
"opentelemetry_semantic_conventions": {:hex, :opentelemetry_semantic_conventions, "0.2.0", "b67fe459c2938fcab341cb0951c44860c62347c005ace1b50f8402576f241435", [:mix, :rebar3], [], "hexpm", "d61fa1f5639ee8668d74b527e6806e0503efc55a42db7b5f39939d84c07d6895"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"poison": {:hex, :poison, "5.0.0", "d2b54589ab4157bbb82ec2050757779bfed724463a544b6e20d79855a9e43b24", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "11dc6117c501b80c62a7594f941d043982a1bd05a1184280c0d9166eb4d8d3fc"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
Expand Down
43 changes: 42 additions & 1 deletion test/tesla/middleware/timeout_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,26 @@ defmodule Tesla.Middleware.TimeoutTest do
end
end

defmodule OtelTimeoutClient do
use Tesla

plug Tesla.Middleware.Timeout,
timeout: 100,
task_module: OpentelemetryProcessPropagator.Task

adapter fn env ->
case env.url do
"/sleep_50ms" ->
Process.sleep(50)
{:ok, %{env | status: 200}}

"/sleep_150ms" ->
Process.sleep(150)
{:ok, %{env | status: 200}}
end
end
end

describe "using custom timeout (100ms)" do
test "should return timeout error when the stack timeout" do
assert {:error, :timeout} = Client.get("/sleep_150ms")
Expand Down Expand Up @@ -111,7 +131,7 @@ defmodule Tesla.Middleware.TimeoutTest do
[_, {timeout_module, _, _, module_file_info} | _] = __STACKTRACE__

assert Tesla.Middleware.Timeout == timeout_module
assert module_file_info == [file: 'lib/tesla/middleware/timeout.ex', line: 45]
assert module_file_info == [file: 'lib/tesla/middleware/timeout.ex', line: 59]
else
_ ->
flunk("Expected exception to be thrown")
Expand All @@ -126,4 +146,25 @@ defmodule Tesla.Middleware.TimeoutTest do
assert catch_exit(Client.get("/exit")) == :exit_value
end
end

describe "swapping task_module for OpentelemetryProcessPropagator.Task" do
test "should return timeout error when the stack timeout" do
assert {:error, :timeout} = OtelTimeoutClient.get("/sleep_150ms")
end

test "should return the response when not timeout" do
assert {:ok, %Tesla.Env{status: 200}} = OtelTimeoutClient.get("/sleep_50ms")
end

test "should not kill calling process" do
Process.flag(:trap_exit, true)

pid =
spawn_link(fn ->
assert {:error, :timeout} = Client.get("/sleep_150ms")
end)

assert_receive {:EXIT, ^pid, :normal}, 200
end
end
end

0 comments on commit 04a94e6

Please sign in to comment.