otp-thinkinglisted
Install: claude install-skill ahmedxx99/claude-code-elixir
# OTP Thinking
Paradigm shifts for OTP design. These insights challenge typical concurrency and state management patterns.
## The Iron Law
```
GENSERVER IS A BOTTLENECK BY DESIGN
```
A GenServer processes ONE message at a time. Before creating one, ask:
1. Do I actually need serialized access?
2. Will this become a throughput bottleneck?
3. Can reads bypass the GenServer via ETS?
**The ETS pattern:** GenServer owns ETS table, writes serialize through GenServer, reads bypass it entirely with `:read_concurrency`.
**No exceptions:** Don't wrap stateless functions in GenServer. Don't create GenServer "for organization".
## GenServer Patterns
| Function | Use For |
|----------|---------|
| `call/3` | Synchronous requests expecting replies |
| `cast/2` | Fire-and-forget messages |
**When in doubt, use `call`** to ensure back-pressure. Set appropriate timeouts for `call/3`.
Use `handle_continue/2` for post-init work—keeps `init/1` fast and non-blocking.
## Task.Supervisor, Not Task.async
`Task.async` spawns a **linked** process—if task crashes, caller crashes too.
| Pattern | On task crash |
|---------|---------------|
| `Task.async/1` | Caller crashes (linked, unsupervised) |
| `Task.Supervisor.async/2` | Caller crashes (linked, supervised) |
| `Task.Supervisor.async_nolink/2` | Caller survives, can handle error |
**Use Task.Supervisor for:** Production code, graceful shutdown, observability, `async_nolink`.
**Use Task.async for:** Quick experiments, scripts, when cra