wktdev
In the following code I use agent to “save state” of a list and then I update the list.
(I know elixir does not have objects but naming my functions as such helps me reason about the code )
defmodule M do
def create_object() do
{:ok, pid} = Agent.start_link(fn -> [1, 2, 3] end)
pid
end
def update_object(pid, new_data) do
Agent.update(pid, fn (state) -> state ++ new_data end)
pid
end
def get_object(pid) do
IO.inspect Agent.get(pid, &(&1))
end
end
M.create_object() |> M.update_object([4, 5]) |> M.get_object()
The following code has the same result but does not use agent. What can the code that does use agent do that the following code can not? Asking this question is my attempt to see what I am not understanding.
defmodule M do
def create_object() do
obj = [1, 2, 3]
obj
end
def update_object(obj, new_data) do
obj = obj ++ new_data
obj
end
def get_object(obj) do
IO.inspect obj
obj
end
end
M.create_object() |> M.update_object([4, 5]) |> M.get_object()
Trending in Questions
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
Hello,
I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
Documentation
While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
So my question is quite simple and i have found no conclusive answer on forum, google or AI.
Should we use :erlang.float for Integer to ...
New
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
Other Trending Topics
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hi there! We created Gust: A task orchestrator inspired by Airflow.
For those who have never heard about Aiflow, it’s a Python-based wor...
New
Hi everyone!
The first release candidate for the Expert language server project is now available!
We’ve published a press release detai...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
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
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #security











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
hubertlepicki
The main difference is that Agent (or GenServer) runs in it’s own process.
This means that knowing the pid of Agent (or it’s registered name) you can retrieve/save state from different concurrent processes.
You can use Agent to say implement a dynamic configuration for the application. All HTTP requests are handled in their own processses, but they would be able to access this shared configuration. Then, you could update the configuration say from iex shell and it would be picked up by all other processes now on.
peerreynders
Hubert’s reply is correct
I’d like to explore some aspects in more depth and detail.
First of all many of us are still scratching our head in terms of finding valid use cases for Agents as evidenced by this topic:
Discussion about uses for Agent Processes
Hubert’s use case of changing the configuration state of a running system through the shell is a viable one - though I would imagine that sending a function to update the state is inherently more risky than simply replacing the old state with a new, known to be consistent, state.
Then there is the choice of your example - it is inherently sequential. I recommend that you watch:
Erlang Master Class 2: Video 1 - Turning sequential code into concurrent code
Your example forces a particular ordering on the sequence of operations which doesn’t take advantage of the capabilities of the Agent - there are no independent, concurrent parts in your computation.
Your use of an Agent can be roughly expressed as a
GenServerlike thisAgents are often used to introduce the concept of processes because the code looks initially much less arcane than
GenServercode. In your example the client code provides the function that is updating the Agent’s state. In myGenServerbased code I fixed the “meaning” of “update” in a module function to appendingnew_datato theGenServerstate.The point I’m trying to make is that
Agentcan be viewed as aGenServerturned-inside-out. With aGenServerthe functionality to change process state is fixed within the callback module - with anAgentthe computations (functionality) to change process state are provided from outside of the process.The whole point for an
Agent:or a
GenServeris that numerous (tens, hundreds, thousands, … of) other processes can concurrently append data to the list managed by process
pidwithout sharing state.In a typical conventional multi-threaded program that list would often be shared so that each thread could append its own data to the shared list - so the list would have to be explicitly protected by locks, mutexes, etc.
Now
Agent.updateandGenServer.callare synchronous calls - so they will block until the target process receives the message and sends a reply. For asynchronous processing there isAgent.castandGenServer.castNow when
update_object/2returns there is no guarantee that the list inpidhas been updated yet. But the code still works - becauseget_object/1is still synchronous and because here messages are processed in the order of arrival, i.e.{:update,new_data}before:get, the list will be updated before the state is returned.wktdev
I will need to read your response a bunch to understand it but…
I think a perfect example to help someone like me to understand agents would be a minimalist terminal chat application that uses them. In my head I have an image of firing up the script in one terminal with a user name and then firing up the same script in a different terminal with a different user name and then they communicate with each other. I’ve seen this kind of thing as a big bulky “Chat server” and using Phoenix but not as a slimmed down “light” example with Agents that can fit on a page or two.
peerreynders
Something like that is here. But it is implemented with the concurrency primitives
spawn,sendandreceive. Now it would possible to useGenServerinstead.Using
Agentwould not be a good fit.wktdev
Is it bad practice to mix/match spawn and agent. I have this image in my head of spawn recursing to create the “main process” and an agent is being used as the entry to join the chat as a user. If this sounds stupid just ignore me - I’m new
peerreynders
Both
AgentandGenServerare part of the Elixir OTP library and are built on top of the concurrency primitives - that is why you don’t mix them.That being said it is helpful to know how processes work on the primitive level before using OTP. So looking at Processes is a good start.
hubertlepicki
I think you generally don’t use bare Erlang/Elixir processes without relying on GenServer (or Agent) in real life. The only cases where I ever did that, was when I simply wanted to start a background job that I did not really care or interacted with afterwards. Such as sending e-mail.
And even then, it usually evolved to a GenServer(s) since this gives some sort of ability to limit the concurrency, instll some monitoring etc.
Spawning bare bones processes is quickly becoming inconvenient.
smpallen99
Like the other answers say, Agents are uses to manage state across different processes. For example, in my Chat app, I use an Agent to store who’s tying state. When someone starts typing, their typing state is send to the agent. When someone else starts typing that process can query the agent for others typing in that room.
They can also be used for saving state across different web requests. For example, my authentication plug stores the user’s session key in an agent when they login. On each subsequent web request, the plug checks for their session key in the agent and sets current_user in the conn assigns to the user data (stored as the value in the agent).
In a nut shell, I use Agents to save state that I don’t need persisted across server restarts. They are faster then using a database. If I need more than just simple put, update, get access I will use a GenServer.
There are other approaches that can use as an alternative to Agents; ETS, Process dictionary, GenServer, and database.
wktdev
The chat example doesn’t work. It’s outdated.
peerreynders
A lot can be learned by updating outdated code.
works even on http://elixirplayground.com/
GenServer version
Elixir playground doesn’t support
GenServer.stop.And finally the Agent version … it’s wrong in so many ways.
The following is more in keeping with how an Agent is actually supposed to be used - as a state container. As a result the chat is now peer-to-peer - there is no “server” as such. However the clients do not keep the “room” as part of their own state - that is farmed out to the agent and manipulated through the anonymous functions created by the various
handle_xfunctions.However it still remains a strange way of using an agent.