Skip to content

Commit

Permalink
Add support for passing tasks to async middleware (#680)
Browse files Browse the repository at this point in the history
The docs mentioned the option but the code did not support it.
  • Loading branch information
maartenvanvliet authored and benwilson512 committed Feb 26, 2019
1 parent de0f0a2 commit 9adb7c5
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 7 deletions.
9 changes: 7 additions & 2 deletions lib/absinthe/middleware/async.ex
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,11 @@ defmodule Absinthe.Middleware.Async do
# This function inserts additional middleware into the remaining middleware
# stack for this field. On the next resolution pass, we need to `Task.await` the
# task so we have actual data. Thus, we prepend this module to the middleware stack.
def call(%{state: :unresolved} = res, {fun, opts}) do
task_data = {Task.async(fun), opts}
def call(%{state: :unresolved} = res, {fun, opts}) when is_function(fun),
do: call(res, {Task.async(fun), opts})

def call(%{state: :unresolved} = res, {task, opts}) do
task_data = {task, opts}

%{
res
Expand All @@ -61,6 +64,8 @@ defmodule Absinthe.Middleware.Async do
}
end

def call(%{state: :unresolved} = res, %Task{} = task), do: call(res, {task, []})

# This is the clause that gets called on the second pass. There's very little
# to do here. We just need to await the task started in the previous pass.
#
Expand Down
27 changes: 23 additions & 4 deletions lib/absinthe/resolution/helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,27 @@ defmodule Absinthe.Resolution.Helpers do
This is a helper function for using the `Absinthe.Middleware.Async`.
Forbidden in mutation fields. (TODO: actually enforce this)
## Options
- `:timeout` default: `30_000`. The maximum timeout to wait for running
the task.
## Example
Using the `Absinthe.Resolution.Helpers.async/1` helper function:
```elixir
field :time_consuming, :thing do
resolve fn _, _, _ ->
async(fn ->
{:ok, long_time_consuming_function()}
end)
end
end
```
"""
@spec async((() -> term)) :: {:middleware, Middleware.Async, term}
@spec async((() -> term), Keyword.t()) :: {:middleware, Middleware.Async, term}
@spec async((() -> term), opts :: [{:timeout, pos_integer}]) ::
{:middleware, Middleware.Async, term}
def async(fun, opts \\ []) do
{:middleware, Middleware.Async, {fun, opts}}
end
Expand All @@ -29,10 +47,11 @@ defmodule Absinthe.Resolution.Helpers do
Helper function for creating `Absinthe.Middleware.Batch`
## Options
- `:timeout` default: `5_000`. The maximum timeout to wait for running
- `:timeout` default: `5_000`. The maximum timeout to wait for running
a batch.
# Example
## Example
Raw usage:
```elixir
object :post do
Expand Down
37 changes: 36 additions & 1 deletion test/absinthe/middleware/async_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,24 @@ defmodule Absinthe.Middleware.AsyncTest do
{:ok, nil}
end)
end

field :async_bare_thing_with_opts, :string do
resolve fn _, _, _ ->
task = Task.async(fn ->
{:ok, "bare task"}
end)
{:middleware, Elixir.Absinthe.Middleware.Async, {task, []}}
end
end

field :async_bare_thing, :string do
resolve fn _, _, _ ->
task = Task.async(fn ->
{:ok, "bare task"}
end)
{:middleware, Elixir.Absinthe.Middleware.Async, task}
end
end
end

def cool_async(fun) do
Expand All @@ -37,7 +55,24 @@ defmodule Absinthe.Middleware.AsyncTest do
end
end

test "can resolve a field using the normal async helper" do
test "can resolve a field using the bare api with opts" do
doc = """
{asyncBareThingWithOpts}
"""

assert {:ok, %{data: %{"asyncBareThingWithOpts" => "bare task"}}} == Absinthe.run(doc, Schema)
end

test "can resolve a field using the bare api" do
doc = """
{asyncBareThing}
"""

assert {:ok, %{data: %{"asyncBareThing" => "bare task"}}} == Absinthe.run(doc, Schema)
end


test "can resolve a field using the normal test helper" do
doc = """
{asyncThing}
"""
Expand Down

0 comments on commit 9adb7c5

Please sign in to comment.