Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

08112022 Supervisors - Questions aplenty #18

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
elixir 1.14.0-otp-25
elixir 1.14.1-otp-25
erlang 25.1.1
76 changes: 72 additions & 4 deletions exercises/creature_spawner.livemd
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ Implement the `Monster` process as documented below.
```elixir
defmodule Monster do
use GenServer
@enforce_keys [:health]
defstruct @enforce_keys

@doc """
Start the `Monster` process.
Expand All @@ -110,9 +112,11 @@ defmodule Monster do

iex> {:ok, pid} = Monster.start_link([])
"""

# BrookQuestion - The Start signature options is killing me "name: opts[:name]"
# Sesame Street it for me please
def start_link(opts) do
# IO.inspect/2 to observe when a `Monster` process starts.
IO.inspect(opts, label: "Monster Started")
GenServer.start_link(__MODULE__, opts, name: opts[:name])
end

@doc """
Expand All @@ -128,6 +132,7 @@ defmodule Monster do
%{health: 70}
"""
def attack(monster_pid, amount) do
GenServer.cast(monster_pid, {:attack, amount})
end

@doc """
Expand All @@ -140,6 +145,7 @@ defmodule Monster do
100
"""
def health(monster_pid) do
GenServer.call(monster_pid, :health)
end

@doc """
Expand All @@ -153,7 +159,8 @@ defmodule Monster do
%{health: 100}
"""
@impl true
def init(_opts) do
def init(opts) do
{:ok, %{health: 100}}
end

@doc """
Expand All @@ -174,8 +181,26 @@ defmodule Monster do
"""
@impl true
def handle_cast({:attack, damage}, state) do
new_health = state.health - damage

if new_health <= 0 do
raise "dying!"
else
{:noreply, %{state | health: new_health}}
end
end

# BrookQuestion - Why is my implementation not working? I don't get it:

# case state.health - damage do
# 0 ->
# raise("Morir! Morir!")

# true ->
# new_state = Map.replace(state, :health, state.health - damage)
# {:noreply, new_state}
# end

@doc """
Callback function to retrieve the current health of a monster.

Expand All @@ -187,10 +212,21 @@ defmodule Monster do
"""
@impl true
def handle_call(:health, _from, state) do
{:reply, state.health, state}
end
end
```

```elixir
# {:ok, pid} = GenServer.start_link(Monster, [])
# GenServer.call(pid, :health)
```

```elixir
# GenServer.cast(pid, {:attack, 20})
# :sys.get_state(pid)
```

## Supervisor

Create three named `Monster` processes under a single supervisor. When one `Monster` process dies after its health reaches zero, another should be restarted in it's place.
Expand Down Expand Up @@ -240,7 +276,22 @@ Supervisor.start_link(children, strategy: :one_for_one)
Enter your solution below.

```elixir
children = [
%{
id: :Monster1,
start: {Monster, :start_link, [[name: :monster1]]}
},
%{
id: :Monster2,
start: {Monster, :start_link, [[name: :monster2]]}
},
%{
id: :Monster3,
start: {Monster, :start_link, [[name: :monster3]]}
}
]

{:ok, supervisor_pid} = Supervisor.start_link(children, strategy: :one_for_one)
```

Call `Monster.attack/1` on your monster processes to ensure they are restarted.
Expand All @@ -256,7 +307,7 @@ Monster.attack(:monster1, 110)
</details>

```elixir

# Monster.attack(:monster1, 110)
```

## Bonus: Hero
Expand Down Expand Up @@ -297,9 +348,26 @@ end
</details>

```elixir
#BrookQuestion: in which instances we choose Process.send instead of GenServer.call?


defp schedule_attack() do
Process.send_after(self(), :attack_monsters, 1000)
end

def handle_info(:attack_monsters, state) do
Supervisor.which_children(:rpg_supervisor)
|> Enum.each(fn
{_name, pid, :worker, [Monster]} -> Monster.attack(pid, Enum.random(1..10))
_ -> :ok
end)

```

```elixir
Hero.start_link(supervisor_pid)
```

Start the `Hero` process with three other `Monster` processes in the same supervisor. Make the supervisor a named supervisor so you can find all of its child processes with [Supervisor.which_children/1](https://hexdocs.pm/elixir/Supervisor.html#which_children/1).

<details style="background-color: lightgreen; padding: 1rem; margin: 1rem 0;">
Expand Down
19 changes: 18 additions & 1 deletion exercises/dominoes.livemd
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,24 @@ Supervisor.start_link(children, strategy: :rest_for_one)
Keep in mind, if you have already started a named process, the supervisor might crash when you attempt to start it again. Re-evaluate the cell after the livebook crashes to resolve this issue.

```elixir
# BrookQuestion Can we go over the start signature thingy again?

children = [
%{
id: :domino1,
start: {Domino, :start_link, [[name: :domino1]]}
},
%{
id: :domino2,
start: {Domino, :start_link, [[name: :domino2]]}
},
%{
id: :domino3,
start: {Domino, :start_link, [[name: :domino3]]}
}
]

{:ok, supervisor_pid} = Supervisor.start_link(children, strategy: :rest_for_one)
```

Send your dominos messages to ensure they are crashing in the correct order. They will log a message that demonstrates the `Domino.start_link/1` function was called again.
Expand All @@ -114,7 +131,7 @@ Process.send(:domino_name, :fall, [])
Test sending each `Domino` process a message individually.

```elixir

Process.send(:domino2, :fall, [])
```

## Commit Your Progress
Expand Down
14 changes: 13 additions & 1 deletion exercises/supervised_stack.livemd
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ We've made a slight modification to the `Stack` process by adding a `start_link/
defmodule Stack do
use GenServer

# BrookQuestion - This is how I first tried
# children = [%{id: :stack, start: {__MODULE__, :start_link, []}}]
# Supervisor.start_link(children, strategy: :one_for_one)
# I think I am not grasping the start signature. Guidance, please?

# BrookQuestion - I also do not fully understand the solution cell
# Is that supposed to be all part of the module, or part of it is to be called from outside?

def start_link(opts) do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
Expand Down Expand Up @@ -102,15 +110,19 @@ children = [
Keep in mind, if you have already started a supervisor with the `Stack` process, your livebook may crash. You can resolve this issue by simply re-running the cell below to start the supervisor again.

```elixir
children = [
{Stack, []}
]

{:ok, supervisor_pid} = Supervisor.start_link(children, strategy: :one_for_one)
```

You should be able to send a `:pop` message to the `Stack` process and the [Supervisor](https://hexdocs.pm/elixir/Supervisor.html) will restart the `Stack` process.

Uncomment and evaluate the code below to test your supervisor.

```elixir
# GenServer.call(Stack, :pop)
GenServer.call(Stack, :pop)
```

## Commit Your Progress
Expand Down