Packages
absinthe
1.4.1
1.11.0
1.10.2
1.10.1
1.10.0
1.9.1
1.9.0
1.8.0
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.8
1.6.7
retired
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.6.0-rc.1
1.6.0-rc.0
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.5.0-rc.5
1.5.0-rc.4
1.5.0-rc.3
1.5.0-rc.2
1.5.0-rc.1
1.5.0-rc.0
1.5.0-beta.2
1.5.0-beta.1
1.5.0-beta.0
1.5.0-alpha.4
1.5.0-alpha.3
1.5.0-alpha.2
1.5.0-alpha.1
1.5.0-alpha.0
1.4.16
1.4.15
1.4.14
1.4.13
1.4.12
1.4.11
1.4.10
1.4.9
1.4.8
retired
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-rc.3
1.4.0-rc.2
1.4.0-rc.1
1.4.0-rc.0
1.4.0-beta.5
1.4.0-beta.4
1.4.0-beta.3
1.4.0-beta.2
1.4.0-beta.1
1.3.2
1.3.1
1.3.0
1.3.0-rc.0
1.3.0-beta.2
1.3.0-beta.1
1.3.0-beta.0
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc.0
1.2.0-beta.0
1.2.0-alpha0
1.2.0-alpha.2
1.2.0-alpha.1
1.1.11
1.1.10
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.0
0.5.2
0.5.1
0.5.0
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.2.3
0.2.2
0.2.1
0.1.0
GraphQL for Elixir
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/absinthe/middleware/async.ex
defmodule Absinthe.Middleware.Async do
@moduledoc """
This plugin enables asynchronous execution of a field.
See also `Absinthe.Resolution.Helpers.async/1`
# Example Usage:
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
```
Using the bare plugin API
```elixir
field :time_consuming, :thing do
resolve fn _, _, _ ->
task = Task.async(fn ->
{:ok, long_time_consuming_function()}
end
{:middleware, #{__MODULE__}, task}
end
end
```
This module also serves as an example for how to build middleware that uses the
resolution callbacks.
See the source code and associated comments for further details.
"""
@behaviour Absinthe.Middleware
@behaviour Absinthe.Plugin
# 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
# the task.
#
# This function suspends resolution, and sets the async flag true in the resolution
# accumulator. This will be used later to determine whether we need to run resolution
# again.
#
# 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}
%{res |
state: :suspended,
acc: Map.put(res.acc, __MODULE__, true),
middleware: [{__MODULE__, task_data} | res.middleware]
}
end
# 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.
#
# Finally, we apply the result to the resolution using a helper function that ensures
# we handle the different tuple results.
#
# The `put_result` function handles setting the appropriate state.
# If the result is an `{:ok, value} | {:error, reasoon}` tuple it will set
# the state to `:resolved`, and if it is another middleware tuple it will
# set the state to unresolved.
def call(%{state: :suspended} = res, {task, opts}) do
result = Task.await(task, opts[:timeout] || 30_000)
res
|> Absinthe.Resolution.put_result(result)
end
# We must set the flag to false because if a previous resolution iteration
# set it to true it needs to go back to false now. It will be set
# back to true if any field uses this plugin again.
def before_resolution(exec) do
put_in(exec.acc[__MODULE__], false)
end
# Nothing to do after resolution for this plugin, so we no-op
def after_resolution(exec), do: exec
# If the flag is set we need to do another resolution phase.
# otherwise, we do not
def pipeline(pipeline, exec) do
case exec.acc do
%{__MODULE__ => true} ->
[Absinthe.Phase.Document.Execution.Resolution | pipeline]
_ ->
pipeline
end
end
end