The model - what is an agent?

Agents are another common implementation in the Elixir concurrency world, especially around the context of state management. agents are pretty much designed for that sole purpose: they exist to be simple wrappers around state! They're incredibly simple to work with. Let's open an IEx window (if we don't already have one open) and begin implementing a simple agent:

iex(1)> {:ok, agent} = Agent.start_link(fn -> %{} end)
{:ok, #PID<0.174.0>}

We start off by initializing our agent with Agent.start_link/1. This function takes in a single argument, which is the function that returns the agent's initial state. In the preceding case we're starting off with a completely blank map:

iex(2)> Agent.update(agent, fn state -> Map.put(state, :foo, "bar") end)
:ok

Then we can update the Agent's internal state with a call to the update function in the Agent module. This takes in a reference to our Agent PID (this ends up being a very similar implementation to the process spawning and returning a reference to the process via the process ID or PID). In the preceding case we're just blindly setting a :foo key to the value of bar, but we could be doing anything here, really. Note that the function called in update must supply the previous agent state as the single argument. Let's prove that out and try calling that without passing an argument to the update inner function:

Agent.update(agent, fn -> %{} end)
** (FunctionClauseError) no function clause matching in Agent.update/3

The following arguments were given to Agent.update/3:

# 1
#PID<0.174.0>

# 2
#Function<20.99386804/0 in :erl_eval.expr/5>

# 3
5000

Attempted function clauses (showing 1 out of 1):

def update(agent, fun, timeout) when is_function(fun, 1)

(elixir) lib/agent.ex:361: Agent.update/3

As expected, this blows up on us with an error about attempting function clauses on the update. It will check to see if the supplied function is a function with an arity of 1! That's the when is_function(fun, 1) guard clause being referenced!

Next, we have a means of getting the data back out of the Agent's internal state:

iex(3)> Agent.get(agent, fn state -> state end)
%{foo: "bar"}

The Agent.get/2 call takes in the Agent reference (the PID of the agent) and the function, again, must take in a single argument and return out something back to the caller. In our case, we're just arbitrarily returning the whole thing!

Finally, we stop the Agent, since we're done setting and getting data out of our Agent process:

iex(4)> Agent.stop(agent)
:ok

 We'll close down the process since we have no more we want to do here.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset