You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In the previous chapter we used agents to represent our buckets. In the first chapter, we specified we would like to name each bucket so we can do the following:
11
+
In the [previous chapter](/getting-started/mix-otp/agent.html) we used agents to represent our buckets. In the first chapter, we specified we would like to name each bucket so we can do the following:
12
12
13
13
```elixir
14
14
CREATE shopping
@@ -149,20 +149,20 @@ Our test should pass right out of the box!
149
149
To shutdown the registry, we are simply sending a `:shutdown` signal to its process when our test finishes. While this solution is ok for tests, if there is a need to stop a `GenServer` as part of the application logic, it is best to define a `stop/1` function that sends a `call` message causing the server to stop:
150
150
151
151
```elixir
152
-
## Client API
152
+
## Client API
153
153
154
-
@doc """
155
-
Stops the registry.
156
-
"""
157
-
defstop(server) do
158
-
GenServer.call(server, :stop)
159
-
end
154
+
@doc """
155
+
Stops the registry.
156
+
"""
157
+
defstop(server) do
158
+
GenServer.call(server, :stop)
159
+
end
160
160
161
-
## Server Callbacks
161
+
## Server Callbacks
162
162
163
-
defhandle_call(:stop, _from, state) do
164
-
{:stop, :normal, :ok, state}
165
-
end
163
+
defhandle_call(:stop, _from, state) do
164
+
{:stop, :normal, :ok, state}
165
+
end
166
166
```
167
167
168
168
In the example above, the new `handle_call/3` clause is returning the atom `:stop`, along side the reason the server is being stopped (`:normal`), the reply `:ok` and the server state.
@@ -172,12 +172,12 @@ In the example above, the new `handle_call/3` clause is returning the atom `:sto
172
172
Our registry is almost complete. The only remaining issue is that the registry may become stale if a bucket stops or crashes. Let's add a test to `KV.RegistryTest` that exposes this bug:
173
173
174
174
```elixir
175
-
test "removes buckets on exit", %{registry: registry} do
The test above will fail on the last assertion as the bucket name remains in the registry even after we stop the bucket process.
@@ -202,43 +202,43 @@ Note `Process.monitor(pid)` returns a unique reference that allows us to match u
202
202
Let's reimplement the server callbacks to fix the bug and make the test pass. First, we will modify the GenServer state to two dictionaries: one that contains `name -> pid` and another that holds `ref -> name`. Then we need to monitor the buckets on `handle_cast/2` as well as implement a `handle_info/2` callback to handle the monitoring messages. The full server callbacks implementation is shown below:
203
203
204
204
```elixir
205
-
## Server callbacks
205
+
## Server callbacks
206
206
207
-
definit(:ok) do
208
-
names =HashDict.new
209
-
refs =HashDict.new
210
-
{:ok, {names, refs}}
211
-
end
207
+
definit(:ok) do
208
+
names =HashDict.new
209
+
refs =HashDict.new
210
+
{:ok, {names, refs}}
211
+
end
212
212
213
-
defhandle_call({:lookup, name}, _from, {names, _} = state) do
214
-
{:reply, HashDict.fetch(names, name), state}
215
-
end
213
+
defhandle_call({:lookup, name}, _from, {names, _} = state) do
214
+
{:reply, HashDict.fetch(names, name), state}
215
+
end
216
216
217
-
defhandle_call(:stop, _from, state) do
218
-
{:stop, :normal, :ok, state}
219
-
end
217
+
defhandle_call(:stop, _from, state) do
218
+
{:stop, :normal, :ok, state}
219
+
end
220
220
221
-
defhandle_cast({:create, name}, {names, refs}) do
222
-
ifHashDict.has_key?(names, name) do
223
-
{:noreply, {names, refs}}
224
-
else
225
-
{:ok, pid} =KV.Bucket.start_link()
226
-
ref =Process.monitor(pid)
227
-
refs =HashDict.put(refs, ref, name)
228
-
names =HashDict.put(names, name, pid)
229
-
{:noreply, {names, refs}}
221
+
defhandle_cast({:create, name}, {names, refs}) do
222
+
ifHashDict.has_key?(names, name) do
223
+
{:noreply, {names, refs}}
224
+
else
225
+
{:ok, pid} =KV.Bucket.start_link()
226
+
ref =Process.monitor(pid)
227
+
refs =HashDict.put(refs, ref, name)
228
+
names =HashDict.put(names, name, pid)
229
+
{:noreply, {names, refs}}
230
+
end
230
231
end
231
-
end
232
232
233
-
defhandle_info({:DOWN, ref, :process, _pid, _reason}, {names, refs}) do
234
-
{name, refs} =HashDict.pop(refs, ref)
235
-
names =HashDict.delete(names, name)
236
-
{:noreply, {names, refs}}
237
-
end
233
+
defhandle_info({:DOWN, ref, :process, _pid, _reason}, {names, refs}) do
234
+
{name, refs} =HashDict.pop(refs, ref)
235
+
names =HashDict.delete(names, name)
236
+
{:noreply, {names, refs}}
237
+
end
238
238
239
-
defhandle_info(_msg, state) do
240
-
{:noreply, state}
241
-
end
239
+
defhandle_info(_msg, state) do
240
+
{:noreply, state}
241
+
end
242
242
```
243
243
244
244
Observe that we were able to considerably change the server implementation without changing any of the client API. That's one of the benefits of explicitly segregating the server and the client.
Copy file name to clipboardExpand all lines: getting-started/processes.markdown
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -61,7 +61,7 @@ iex> receive do
61
61
"world"
62
62
```
63
63
64
-
When a message is sent to a process, the message is stored in the process mailbox. The `receive/1` block goes through the current process mailbox searching for a message that matches any of the given patterns. `receive/1` supports many clauses, like `case/2`, as well as guards in the clauses.
64
+
When a message is sent to a process, the message is stored in the process mailbox. The `receive/1` block goes through the current process mailbox searching for a message that matches any of the given patterns. `receive/1` supports guards and many clauses, such as `case/2`.
65
65
66
66
If there is no message in the mailbox matching any of the patterns, the current process will wait until a matching message arrives. A timeout can also be specified:
0 commit comments