Timeouts in Ash work a bit differently than other tools. The following considerations must be taken into account:
- If you run a resource action in a transaction, then the timeout applies to the entire transaction.
If the resource action you are running, and any of its
touches_resourcesis already in a transaction then the timeout is ignored, as the outer transaction is handling the timeout.
- If the resource is not in a transaction, and supports async execution (ash_postgres does), then everything is run in a task and awaited with the provided timeout.
- If the data layer of the resource does not support timeouts, or async execution then timeouts are ignored.
As of the writing of this guide, none of the API extensions support specifying a timeout. If/when they do, they will simply run the action they are meant to run in a
You have a few options.
You can specify a timeout when you call an action. This takes the highest precedence.
MyApi.read!(query, timeout: :timer.seconds(30))
You can specify one using
Ash.Query.timeout/2. This can be useful if you want to conditionally set a timeout based on the details of the request. For example, you might do something like this:
# in your resource defmodule MyApp.SetReportTimeout do use Ash.Resource.Preparation def prepare(query, _, _) do if Ash.Query.get_argument(query, :full_report) do Ash.Query.timeout(query, :timer.minutes(3)) else Ash.Query.timeout(query, :timer.minutes(1)) end end end actions do read :report_items do argument :full_report, :boolean, default: false prepare MyApp.SetReportTimeout end end
And you can specify a default timeout on the Api module that you call your resources with. Overriding an api with a default timeout requires providing a timeout of
:infinity in one of the other methods.
execution do timeout :timer.seconds(30) # this is the default end
Keep in mind, you can’t specify timeouts in a before_action or after_action hook, because at that point you are already “within” the code that should have a timeout applied.