spacebat
Using an Ash Resource with a Dynamic Repository
Hi, we are writing an application that will have its own single/static database, as well as needing to manage connections to an arbitrary number of other databases. Ecto supports this and I wonder if there are any Ash-specific twists to this approach?
If it simplifies things, I think there would be some resources that are always from a preconfigured database, while some other resources would always come from dynamic repos.
Marked As Solved
spacebat
Hey I got it working with the tracer - having not used tracers before and couldn’t find examples of use was the problem. Now I’m worried that the tracer is being called everywhere - is there a way to only turn on the tracer for the duration/scope of a dynamic repo query?
Thanks for all your help!
The preparation:
prepare fn query, context ->
if %{arguments: %{tenant: tenant}} = query do
pid = Dyndb.Repo.get_connection!(tenant)
Dyndb.DynamicRepoTracer.set_span_context({Dyndb.Repo, pid})
end
query
end
…and the custom part of the tracer…
@impl Ash.Tracer
def get_span_context() do
Process.get(:dynamic_repo_tracer)
end
@impl Ash.Tracer
def set_span_context({repo_module, repo_pid} = dynamic_repo) do
Process.put(:dynamic_repo_tracer, dynamic_repo)
repo_module.put_dynamic_repo(repo_pid)
:ok
end
The github repo has been updated.
Also Liked
zachdaniel
To do that with Ash the way it generally works is that you can set a context in your action to set (or override the default) repo. For example:
read :read do
prepare fn query, _ ->
repo = figure_out_repo()
Ash.Query.set_context(query, %{data_layer: %{repo: repo}})
end
end
You can abstract this using a module-backed preparation, and attach it to a resource using the global preparations block in the resource, to trigger it on all queries:
preparations do
prepare SetDynamicRepo
end
Not necessarily a full breakdown, but that should give you a starting point ![]()
zachdaniel
Totally, makes sense. We ultimately want Ash to be able to support all of those models too, even though naturally database per tenant will be a bit more challenging than the alternatives. I could even see a case for building database-per-tenant multi tenancy into ash_postgres as a first class thing at some point.
zachdaniel
So, there are two relevant answers here.
Changes are the equivalent of preparations for other action types
Preparations are for read actions only, but changes can do the same thing for all other action types.
changes do
change SetDynamicRepo
end
Keeping process context
For this, you need to add an Ash.Tracer. Ash.Tracer can “move” process context from one process to any process that Ash starts.
defmodule YourApp.DynamicRepoTracer do
use Ash.Tracer
def get_process_context() do
get_dynamic_repo()
end
def set_process_context(repo) do
set_dynamic_repo(repo)
end
end
And then you can configure the tracer statically:
config :ash, tracer: [YourApp.DynamicRepoTracer]
YMMV on using put_dynamic_repo, but will be interested to hear how it goes if you go that route.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









