Day 02 Core Concepts

Processes & Concurrency

Elixir's killer feature is concurrency. BEAM processes are lighter than OS threads — you can spawn a million of them. Today you learn to spawn processes, send messages, and build supervised process trees.

~1 hour Hands-on Precision AI Academy

Today’s Objective

Elixir's killer feature is concurrency. BEAM processes are lighter than OS threads — you can spawn a million of them. Today you learn to spawn processes, send messages, and build supervised process trees.

spawn/1 creates a new process running a function. Each process has a unique PID. Processes communicate only by sending messages — no shared memory. send(pid, message) sends; receive do...end receives. self() returns the current PID. Process.alive?(pid) checks if a process is running. spawn_link/1 creates a bidirectional link — if one crashes, the other crashes too.

GenServer: The Building Block

GenServer (Generic Server) is a behaviour (interface) that implements a client-server process pattern. You define handle_call/3 (synchronous), handle_cast/2 (async), init/1, and handle_info/2. GenServer.start_link/2 starts it; GenServer.call/2 sends synchronous messages; GenServer.cast/2 sends async. All state lives in the GenServer process — no shared state across processes, no locks needed.

OTP Supervisors

A Supervisor monitors child processes and restarts them on crash. Restart strategies: one_for_one (restart only the crashed child), one_for_all (restart all if one crashes), rest_for_one (restart crashed + those started after it). Supervisors form trees — the top-level supervisor rarely crashes, and lower-level process crashes are contained and auto-recovered. This is the OTP fault-tolerance model.

elixir
ELIXIR
defmodule Counter do use GenServer # Client API def start_link(initial \\ 0) do GenServer.start_link(__MODULE__, initial, name: __MODULE__) end def increment, do: GenServer.cast(__MODULE__, :increment) def decrement, do: GenServer.cast(__MODULE__, :decrement) def value, do: GenServer.call(__MODULE__, :value) # Server callbacks @impl true def init(count), do: {:ok, count} @impl true def handle_call(:value, _from, count) do {:reply, count, count} end @impl true def handle_cast(:increment, count), do: {:noreply, count + 1} def handle_cast(:decrement, count), do: {:noreply, count - 1}
end

# Usage
{:ok, _pid} = Counter.start_link(0)
Counter.increment()
Counter.increment()
Counter.increment()
IO.puts Counter.value()  # 3
Use GenServer.call/2 for operations where you need a response. Use GenServer.cast/2 for fire-and-forget operations. Never do slow work inside handle_call — it blocks all callers during that time.
📝 Day 2 Exercise Build a Concurrent Cache
  1. Create a new Mix project: mix new cache
  2. Implement a Cache GenServer that stores a map of key-value pairs
  3. Add get/1, put/2, and delete/1 client functions
  4. Add a TTL (time-to-live): entries expire after 60 seconds using Process.send_after
  5. Test it: put 5 keys, get them back, wait for expiry, verify they are gone

Supporting Resources

Go deeper with these references.

Elixir Docs
Official Elixir Documentation Complete language reference including guides, library docs, and mix tasks.
HexDocs
Phoenix Framework Docs Full reference for Phoenix, the most popular Elixir web framework.
Elixir School
Elixir School Curriculum Community-driven step-by-step curriculum for learning Elixir.

Day 2 Checkpoint

Before moving on, make sure you can answer these without looking:

Continue To Day 3
Phoenix Framework Basics