From f1cd1486849dddea42e06ddca40622584ff433a3 Mon Sep 17 00:00:00 2001 From: Randall Theuns Date: Sun, 8 Dec 2024 10:55:37 +0100 Subject: [PATCH 1/3] Make task implementation for async configurable --- guides/telemetry.md | 8 ++++++++ lib/absinthe/middleware/async.ex | 11 ++--------- lib/absinthe/middleware/batch.ex | 11 ++--------- lib/absinthe/utils.ex | 20 ++++++++++++++++++++ 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/guides/telemetry.md b/guides/telemetry.md index a9c607b878..a727fb6066 100644 --- a/guides/telemetry.md +++ b/guides/telemetry.md @@ -89,3 +89,11 @@ Instead, you can add the `:opentelemetry_process_propagator` package to your dependencies, which has a `Task.async/1` wrapper that will attach the context automatically. If the package is installed, the middleware will use it in place of the default `Task.async/1`. + +Alternatively, you can configure the `Task` implementation to use: + +```elixir +config :absinthe, task_module: MyTaskModule +``` + +The provided module must support the `async/1` function. diff --git a/lib/absinthe/middleware/async.ex b/lib/absinthe/middleware/async.ex index 52bdaccdb1..5692a3b4f6 100644 --- a/lib/absinthe/middleware/async.ex +++ b/lib/absinthe/middleware/async.ex @@ -38,6 +38,8 @@ defmodule Absinthe.Middleware.Async do @behaviour Absinthe.Middleware @behaviour Absinthe.Plugin + import Absinthe.Utils, only: [async: 1] + # A function has handed resolution off to this middleware. The first argument # is the current resolution struct. The second argument is the function to # execute asynchronously, and opts we'll want to use when it is time to await @@ -110,13 +112,4 @@ defmodule Absinthe.Middleware.Async do pipeline end end - - # Optionally use `async/1` function from `opentelemetry_process_propagator` if available - if Code.ensure_loaded?(OpentelemetryProcessPropagator.Task) do - @spec async((-> any)) :: Task.t() - defdelegate async(fun), to: OpentelemetryProcessPropagator.Task - else - @spec async((-> any)) :: Task.t() - defdelegate async(fun), to: Task - end end diff --git a/lib/absinthe/middleware/batch.ex b/lib/absinthe/middleware/batch.ex index 4dc25ab159..98fd161d1e 100644 --- a/lib/absinthe/middleware/batch.ex +++ b/lib/absinthe/middleware/batch.ex @@ -62,6 +62,8 @@ defmodule Absinthe.Middleware.Batch do require Logger + import Absinthe.Utils, only: [async: 1] + @typedoc """ The function to be called with the aggregate batch information. @@ -226,13 +228,4 @@ defmodule Absinthe.Middleware.Batch do pipeline end end - - # Optionally use `async/1` function from `opentelemetry_process_propagator` if available - if Code.ensure_loaded?(OpentelemetryProcessPropagator.Task) do - @spec async((-> any)) :: Task.t() - defdelegate async(fun), to: OpentelemetryProcessPropagator.Task - else - @spec async((-> any)) :: Task.t() - defdelegate async(fun), to: Task - end end diff --git a/lib/absinthe/utils.ex b/lib/absinthe/utils.ex index eaa562566d..0a121b3299 100644 --- a/lib/absinthe/utils.ex +++ b/lib/absinthe/utils.ex @@ -151,4 +151,24 @@ defmodule Absinthe.Utils do #{types ++ directives} """ end + + @spec async((-> any)) :: Task.t() + def async(fun) do + case Application.fetch_env(:absinthe, :task_module) do + {:ok, module} when is_atom(module) -> + module.async(fun) + + _ -> + async_default(fun) + end + end + + # Optionally use `async/1` function from `opentelemetry_process_propagator` if available + if Code.ensure_loaded?(OpentelemetryProcessPropagator.Task) do + @spec async_default((-> any)) :: Task.t() + defdelegate async_default(fun), to: OpentelemetryProcessPropagator.Task, as: :async + else + @spec async_default((-> any)) :: Task.t() + defdelegate async_default(fun), to: Task, as: :async + end end From da380662070053a2f0f2b79f28b60ce08b8705a6 Mon Sep 17 00:00:00 2001 From: Randall Theuns Date: Sun, 8 Dec 2024 16:49:51 +0100 Subject: [PATCH 2/3] Make task_module a compile_env --- lib/absinthe/utils.ex | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/lib/absinthe/utils.ex b/lib/absinthe/utils.ex index 0a121b3299..843623ad0e 100644 --- a/lib/absinthe/utils.ex +++ b/lib/absinthe/utils.ex @@ -152,23 +152,18 @@ defmodule Absinthe.Utils do """ end + task_module = Application.compile_env(:absinthe, :task_module) + @spec async((-> any)) :: Task.t() - def async(fun) do - case Application.fetch_env(:absinthe, :task_module) do - {:ok, module} when is_atom(module) -> - module.async(fun) + cond do + is_atom(task_module) and task_module != nil -> + def async(fun), do: unquote(task_module).async(fun) - _ -> - async_default(fun) - end - end + # Optionally use `async/1` function from `opentelemetry_process_propagator` if available + Code.ensure_loaded?(OpentelemetryProcessPropagator.Task) -> + defdelegate async(fun), to: OpentelemetryProcessPropagator.Task - # Optionally use `async/1` function from `opentelemetry_process_propagator` if available - if Code.ensure_loaded?(OpentelemetryProcessPropagator.Task) do - @spec async_default((-> any)) :: Task.t() - defdelegate async_default(fun), to: OpentelemetryProcessPropagator.Task, as: :async - else - @spec async_default((-> any)) :: Task.t() - defdelegate async_default(fun), to: Task, as: :async + true -> + defdelegate async(fun), to: Task end end From 3b7795422595547286350ac965426d1769b52b86 Mon Sep 17 00:00:00 2001 From: Randall Theuns Date: Mon, 9 Dec 2024 17:40:57 +0100 Subject: [PATCH 3/3] Explain which config to place the :task_module in --- guides/telemetry.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/guides/telemetry.md b/guides/telemetry.md index a727fb6066..efd509b7ea 100644 --- a/guides/telemetry.md +++ b/guides/telemetry.md @@ -96,4 +96,6 @@ Alternatively, you can configure the `Task` implementation to use: config :absinthe, task_module: MyTaskModule ``` -The provided module must support the `async/1` function. +This is a compile-time option, so it cannot be configured in `runtime.exs`. +Instead, place it in `config.exs` or build-specific configs (`dev.exs`, +`prod.exs`, etc.). The provided module must support the `async/1` function.