byu
Ash Resource Consistency Boundary vs Transactional Boundary
Given a very very simple twist on the canonical Ash Example, I just have a Ticket resource with only an id and name attributes backed by a postgres DB.
In the iex -S mix console, while playing around some more, and exploring a bit…
I execute the following code to create tickets; I see a series of INSERTs where each insert is in its own database transaction.
for i <- 0..5 do
Helpdesk.Support.Ticket
|> Ash.Changeset.for_create(:create, %{name: "Issue #{i}"})
|> Helpdesk.Support.create!()
end
So, in a very loose analogy to DDD, the Ash Resource is akin to an Aggregate Root, where the Ash action also has the job to enforce the bounded context’s business rules of the Aggregate (or Resource).
And not to get sucked into the DDD arguments of whether or not the transactional boundaries must match consistency boundaries (the aggregate root), say I still want a set of action/changes to all succeed or not…
How is that achieved in Ash? How can I get a series of resources acted upon within the same DB transaction?
Like if I wanted something similar to a “DDD Service” that takes two resources and updates them conforming to a business rule, then persisting then in a “Unit of Work” ? – Loose analogies still.
For example, say I have two chess players (each a Resource/Aggregate instance) and I want to update their ranking after a game… I want to increase the winner’s points and decrease the loser’s points, while staying consistent?
Or am I thinking about this all wrong?
Thanks
Most Liked
zachdaniel
so you have a few options. Transactionality is built into Ash action. So using your chess game example, you might have something like this:
# on ChessGame
update :finish_game do
change set_attribute(:complete)
change fn changeset, _ ->
Ash.Changeset.after_action(changeset, fn changeset, game ->
# fetch players and modify their score
# whatever happens here is transactional
end)
end
end
By default things that happen in hooks will be in the same transaction. You can also start your own transactions using Ash.DataLayer.transaction(resource, fn -> end)
If your resources are in the same data layer then this works exactly as you’d expect transactions to work. If you have resources across multiple data layers, a transaction for both will be opened. This makes it technically possible to achieve inconsistency if one transactions loses and the other one doesn’t due to a network error (for example). However, it makes a good effort at cross-data-layer consistency. There are usually some things to keep in mind if you are using cross data layer actions but I won’t go into that here because I don’t think that is the main thing in question ![]()
byu
Ok. Looks like I just need to get my hands dirty and try things to find what’s going to work out best for my situation.
Thanks for showing these options.
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
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex










