Ash FrameworkAF
Ash Framework5mo ago
6 replies
Joan Gavelán

Improving incremental compilation times

Hi there! I need to know what the best practices are when working with Ash resources and related files (calculations, preparations, etc), specifically around avoiding unnecessary dependencies and keeping compilation times low. Things to do, and what not to do.

I originally posted about this on the Elixir Forum (https://elixirforum.com/t/reducing-incremental-compilation-times-in-phoenix-ash-project/72113). The feedback there helped me better analyze my codebase and realize that I may be doing something wrong within Ash resources — and related files — myself, which has increased recompilation times (up to 10s).

My gut is telling me that what I'm doing here might be wrong:

# invitation.ex
# References several modules, which results in many dependencies
change after_action(fn _changeset, invitation, _context ->
         invitation
         |> Ash.load!([establishment: [:organization]], authorize?: false)
         |> MyApp.Emails.InvitationEmail.new()
         |> MyApp.Mailer.serialize()
         |> then(fn serialized_email -> %{"email" => serialized_email} end)
         |> MyApp.Workers.MailerWorker.new()
         |> Oban.insert!()

         {:ok, invitation}
       end)


defmodule MyApp.Establishments.Invitation.Calculations.Url do
  use Ash.Resource.Calculation

  @impl true
  def load(_query, _opts, _context), do: [:id]

  @impl true
  def calculate(records, _opts, _context) do
    Enum.map(records, fn record ->
      # Calling this function caused this module (url.ex) to end up with 39 runtime dependencies
      LamashkaWeb.Endpoint.url() <> "/accept-invitation/#{record.id}"
    end)
  end
end


I'm pretty new to this and had no idea about runtime/compilation dependencies until now, so before I continue with my project I’d better take some time to understand all of this to prevent it from continuing to happen, as it has already impacted my productivity.

Thanks in advance for your help.
Solution
defmodule Your.Resource.Changes.SendInvitationEmail do
  use Ash.Resource.Change

  def change(changeset, _, _) ->
    Ash.Changeset.after_action(changeset, fn _changeset, invitation-> 
     invitation
     |> Ash.load!([establishment: [:organization]], authorize?: false)
     |> MyApp.Emails.InvitationEmail.new()
     |> MyApp.Mailer.serialize()
     |> then(fn serialized_email -> %{"email" => serialized_email} end)
     |> MyApp.Workers.MailerWorker.new()
     |> Oban.insert!()

     {:ok, invitation}
    end)
  end
end
Was this page helpful?