unfode
Suppose I have two states. In C, I can mutate them atomically (either all or none are mutated) using locks:
bool atomic_mutation() {
lock(state1_lock);
lock(state2_lock);
bool success = mutate1(state1);
if (!success) {
unlock(state1_lock);
unlock(state2_lock);
return false;
}
success = mutate2(state2);
if (!success) {
// revert mutate1(state1)
unlock(state1_lock);
unlock(state2_lock);
return false;
}
unlock(state1_lock);
unlock(state2_lock);
return true;
}
I’m new to Elixir. What I’ve learned is that I normally use an Agent to manage a state. But how to achieve atomicity shown above in Elixir? Thanks!
Edit: I fixed the bug in the C code above as pointed out by @al2o3cr
Trending in Questions
Hello!
Suppose you are building workflow (order / task / payment) processing system with the following requirements:
Each workflow con...
New
I’m aware of 2 such projects, are there others?
git: GitHub - team-alembic/realworld: A fullstack Phoenix LiveView application with back...
New
Hi all,
I’m working on a Phoenix project where I need to make external HTTP requests and I’m trying to choose between Req and HTTPoison....
New
Hi everyone.
My team and I have been working on a fairly modest app based around video streaming and chat, but we’ve landed a customer t...
New
Hi,
we run different LLM models across a cluster, with each node loading a configurable subset. Model-specific queues let nodes consume ...
New
Hi all, I’m new here and would like to hear peoples views on my Elixir/Phoenix based game-engine! :smiley:
Mutonex gamedesign was finish...
New
Do we have maintainer of absinthe-graphql/dataloader here? We have a PR that we’d like to merge to the library. Relatively small additive...
New
Other Trending Topics
Hey there,
I haven’t seen a list of useful Elixir specific skills for the popular AI tools yet so I’m starting one here with my first.
...
New
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself.
My main conc...
New
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly)
AI dream has many faces, but general...
New
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
- #ai
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #blog-post
- #ecto-query
- #elixirconf-us
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #elixirconf-eu
- #api
- #forms
- #security
- #hex










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
benwilson512
Hey welcome! The short answer is that if you need shared state and you need to control changes to that state then yeah you would use an agent or GenServer (more generally) and put the state inside that.
In general though as a functional language much of your program design will be avoiding such shared state at all.
unfode
I understand that the functional style avoids shared states as much as possible. But shared states can’t be eliminated in many applications, like databases.
Suppose I have two tables in a database. I need to mutate both tables atomically in a transaction. How to achieve this in Elixir using
AgentorGenServer?One solution is to have an
Agentmanage both tables as one state. However, the downside is poor performance — when processA mutates table1 and processB mutates table2, the two mutations can’t be done in parallel, even if they are independent of each other.benwilson512
I would simply use the database itself for this, it will provide a ton of dedicated tooling for it.
LostKobrakai
How do you make sure multiple actors changes are actually independent?
In the end you’ll surely get to the fact that immutability prevents certain optimizations, but generally the question should be how much those matter to the endproduct.
unfode
Good point.
Mutations of two tables seem surely independent. Can you provide an example?
unfode
Maybe someone wants to build a database in Elixir
LostKobrakai
Put each table in a separate process and they’re independent.
dimitarvp
GenServer.:modify_twenty_things_inside_the_state.Or if a database need be involved, they have their own transaction primitives as others said.
al2o3cr
The BEAM provides the infrastructure, but you need to write the code to glue things together into a consistent distributed system - and to be clear, once you have TWO GenServers you’re trying to make change together you’re in distributed-system territory.
For instance, here’s a very basic “table with a lock” GenServer (see below for notes):
There are a LOT of places where this could be work better / handle concurrency better:
lockand pick the next one to reply to inunlock.handle_callthat the implementation ofunlock/1could use to crash the calling process, since unlocking a table that you haven’t locked is a logic errorProcess.monitorcan help with this, at the cost of additional complexity.Expanding this setup to TWO tables adds some extra complications:
if process A takes lock 1 and then tries to take lock 2, while at the same time process B takes lock 2 and tries to take lock 1 the system is in a classic DEADLOCK situation. The default 5s timeout on
GenServer.callwill eventually pick a winner, but real systems will detect this and complaincoordinating changes to ensure that they either all appear or all do not is still just as tricky as always. You’d need a third process to coordinate the
TableWithLocksand roll back changes if a future change fails.Note that even the code in your example does not produce atomicity - if
mutate2returnsfalse, the changes frommutate1are still visible.Solving this problem correctly is capital-H Hard and the solutions are highly sensitive to exactly what tradeoffs your particular application can tolerate.
unfode
Really appreciate your comprehensive answer!