Skip to content

Commit 9a69133

Browse files
committed
Raise informative error on batched resolver timeout
When the Task that runs a batched resolver times out we currently raise a generic error like this: ** (exit) exited in: Task.await(%Task{owner: #PID<0.15353.21>, pid: #PID<0.15380.21>, ref: #Reference<0.2441152191.2237136897.192020>}, 5000) This provides no context to the engineer debugging the error about the resolver that timed out, making debugging much harder. This change raises a RuntimeError which includes the resolver that timed out along with the arguments it received: Batch resolver timed out after 1 ms. Batch fun: {Absinthe.Middleware.BatchTest.Schema, :slow_field_by_user_id} Batch data: [3, 2, 1] Batch opts: [timeout: 1] This should make the debugging experience a lot better.
1 parent 2ba17d8 commit 9a69133

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

lib/absinthe/middleware/batch.ex

+13-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,19 @@ defmodule Absinthe.Middleware.Batch do
147147
end)
148148
|> Map.new(fn {batch_opts, task, start_time_mono, metadata} ->
149149
timeout = Keyword.get(batch_opts, :timeout, 5_000)
150-
result = Task.await(task, timeout)
150+
151+
result =
152+
try do
153+
Task.await(task, timeout)
154+
catch
155+
:exit, {:timeout, {Task, :await, _}} ->
156+
raise """
157+
Batch resolver timed out after #{timeout} ms.
158+
Batch fun: #{inspect(metadata.batch_fun)}
159+
Batch data: #{inspect(metadata.batch_data)}
160+
Batch opts: #{inspect(metadata.batch_opts)}
161+
"""
162+
end
151163

152164
end_time_mono = System.monotonic_time()
153165
duration = end_time_mono - start_time_mono

test/absinthe/middleware/batch_test.exs

+37
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ defmodule Absinthe.Middleware.BatchTest do
3636
end)
3737
end
3838
end
39+
40+
field :slow_field, :integer do
41+
resolve fn user, _, _ ->
42+
batch(
43+
{__MODULE__, :slow_field_by_user_id},
44+
user.id,
45+
fn batch -> {:ok, Map.get(batch, user.id)} end,
46+
timeout: 1
47+
)
48+
end
49+
end
3950
end
4051

4152
query do
@@ -69,6 +80,11 @@ defmodule Absinthe.Middleware.BatchTest do
6980
def otel_ctx(_, _) do
7081
OpenTelemetry.Ctx.get_value("stored_value", nil)
7182
end
83+
84+
def slow_field_by_user_id(_, ids) do
85+
:timer.sleep(5000)
86+
ids |> Enum.with_index() |> Map.new()
87+
end
7288
end
7389

7490
test "can resolve a field using the normal async helper" do
@@ -150,4 +166,25 @@ defmodule Absinthe.Middleware.BatchTest do
150166

151167
assert {:ok, %{data: %{"ctx" => "some_value"}}} == Absinthe.run(doc, Schema)
152168
end
169+
170+
test "raises when batched resolver times out" do
171+
doc = """
172+
{
173+
users {
174+
slowField
175+
}
176+
}
177+
"""
178+
179+
assert_raise(
180+
RuntimeError,
181+
"""
182+
Batch resolver timed out after 1 ms.
183+
Batch fun: {Absinthe.Middleware.BatchTest.Schema, :slow_field_by_user_id}
184+
Batch data: [3, 2, 1]
185+
Batch opts: [timeout: 1]
186+
""",
187+
fn -> Absinthe.run(doc, Schema) end
188+
)
189+
end
153190
end

0 commit comments

Comments
 (0)