byu
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
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #ai
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #elixirconf-eu
- #metaprogramming
- #hex











Showing Posts 1 to 8- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
zachdaniel
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
Thanks Zach,
Repeating so I understand… two options that you have suggested:
Ash.DataLayer.transaction(resource, fn -> end), which would be outside of an Ash Resource action.With that, I’m hearing that eventual consistency techniques would be required if we were to cross such data layer boundaries. And yes, I’m not wanting to go down a complicated rabbit hole of a multi-bounded-context distributed system (ala multiple project deployments)… Just looking at the scope of keeping things, hopefully,
straight forward simple: single domain, single bounded context, and single data layer.
Thanks! I’ll try those options.
zachdaniel
You can use generic actions to use
Ash.DataLayer.transactionto do arbitrary stuff in any resource.…or you can use the handy
transaction? trueoption for generic actionsbyu
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.
zachdaniel
My pleasure! Feel free to keep the questions coming
brunoripa
Hey @zachdaniel , hi ! One question about something I already bumped into some months ago but then things changed and I had no chance to look into this.
I have an
UserInvitationresource that defines an:approveaction:The user case is: an user requires an invitation and approves it; at this point an user must be created and the invitation must be set to
status: :approved. There is also a notification which sends and email outside the transaction, of course.If I try to compile the code I see the warning about the need to set
required_atomic?totrue. I fix the code with such suggestion, and theafter_actionfunction simply is not executed.What am I missing ? Thanks !
zachdaniel
You’re not returning the changeset that has the after action hook on it
you’re returning the original changeset.
brunoripa
Ok, right. It works now. I was somehow confused by the two different resources involved. Thanks