How to filter using a code interface

There are a couple elements that you’re going to need for this.

The expressions guide shows examples of the kinds of things you can do with expr. In your case what you’re looking for is

filer expr(is_nil(retry_at))

What you might end up wanting to do for simplicities sake is writing an action that uses an after_action hook to detect that no results were returned and tries another query (your second condition).

prepare fn query, _ -> 
  Ash.Query.after_action(query, fn 
    query, [] ->
      # call another read action here
    _query, results ->
      {:ok, results}
  end
end

With that said, you may also be able to accomplish this with sorts and calculations. For example, you could have a calculation that returns the retry_at as long as its in the past or, nil otherwise, something like:

calculate :elligible_retry_at, :datetime, expr(
  if retry_at < now() do
     retry_at
  else
     nil
  end
)

# add a similar calculation that is "created_at only if retry_at is nil"
Ash.Query.sort(query, elligible_retry_at: :asc_nils_last, other_thing: :asc_nils_last)

I think that combined with a limit of 1 would get you what you need.

Docs for sort/limit is here: Ash.Query — ash v3.29.3

Docs for calculations here: Calculations — ash v3.29.3