feat: add source hyperlinks + remove thin from-source.md
Every source reference now links to elixir-lang/elixir at commit f4e1b34. 122 hyperlinks across 11 topic files. Added PATTERN_COMPLETE sentinels. Removed from-source.md (326 lines, shallow) — covered by existing files.
This commit is contained in:
+20
-18
@@ -6,7 +6,7 @@ Analysis of `lib/elixir/lib/supervisor.ex`, `lib/elixir/lib/dynamic_supervisor.e
|
||||
|
||||
## Pattern 1: Static vs Dynamic Supervision — Choose the Right Tool
|
||||
|
||||
**Source:** `lib/elixir/lib/supervisor.ex:1-20` vs `lib/elixir/lib/dynamic_supervisor.ex:1-20`
|
||||
**Source:** [lib/elixir/lib/supervisor.ex#L1](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/supervisor.ex#L1) vs [lib/elixir/lib/dynamic_supervisor.ex#L1](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/dynamic_supervisor.ex#L1)
|
||||
|
||||
**What it does:** Elixir provides two distinct supervisor types:
|
||||
- `Supervisor` — for **static** children known at compile time, started in a defined order
|
||||
@@ -110,7 +110,7 @@ end
|
||||
|
||||
## Pattern 2: PartitionSupervisor for Scalability
|
||||
|
||||
**Source:** `lib/elixir/lib/dynamic_supervisor.ex:60-95` and `lib/elixir/lib/task/supervisor.ex:35-65`
|
||||
**Source:** [lib/elixir/lib/dynamic_supervisor.ex#L60](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/dynamic_supervisor.ex#L60) and [lib/elixir/lib/task/supervisor.ex#L35](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/task/supervisor.ex#L35)
|
||||
|
||||
**What it does:** Both `DynamicSupervisor` and `Task.Supervisor` document the same scalability pattern: when a single supervisor becomes a bottleneck, wrap it in a `PartitionSupervisor` which starts N instances (one per core by default) and routes via a key.
|
||||
|
||||
@@ -206,7 +206,7 @@ end
|
||||
|
||||
## Pattern 3: Supervision Strategies — Choosing the Right Restart Behavior
|
||||
|
||||
**Source:** `lib/elixir/lib/supervisor.ex:315-345` (Strategies section)
|
||||
**Source:** [lib/elixir/lib/supervisor.ex#L315](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/supervisor.ex#L315) (Strategies section)
|
||||
|
||||
**What it does:** Three strategies model three dependency patterns:
|
||||
- `:one_for_one` — independent children (crash of A doesn't affect B)
|
||||
@@ -319,7 +319,7 @@ end
|
||||
|
||||
## Pattern 4: Restart Intensity (`max_restarts` / `max_seconds`)
|
||||
|
||||
**Source:** `lib/elixir/lib/supervisor.ex:309-313`, `lib/elixir/lib/dynamic_supervisor.ex:730-758` (implementation)
|
||||
**Source:** [lib/elixir/lib/supervisor.ex#L309](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/supervisor.ex#L309), [lib/elixir/lib/dynamic_supervisor.ex#L730](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/dynamic_supervisor.ex#L730) (implementation)
|
||||
|
||||
**What it does:** Supervisors track restart frequency. If a child exceeds `max_restarts` within `max_seconds`, the supervisor itself shuts down (escalating the failure to its parent). Defaults: 3 restarts in 5 seconds.
|
||||
|
||||
@@ -422,7 +422,7 @@ Supervisor.init(children,
|
||||
|
||||
## Pattern 5: Restart Values — `:permanent` vs `:transient` vs `:temporary`
|
||||
|
||||
**Source:** `lib/elixir/lib/supervisor.ex:130-152` (Restart values section)
|
||||
**Source:** [lib/elixir/lib/supervisor.ex#L130](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/supervisor.ex#L130) (Restart values section)
|
||||
|
||||
**What it does:** Three restart policies control what happens when a child terminates:
|
||||
- `:permanent` — always restart (default for GenServer/Agent/Supervisor)
|
||||
@@ -522,7 +522,7 @@ end
|
||||
|
||||
## Pattern 6: Automatic Shutdown for Pipeline Supervisors
|
||||
|
||||
**Source:** `lib/elixir/lib/supervisor.ex:349-375` (Automatic shutdown section)
|
||||
**Source:** [lib/elixir/lib/supervisor.ex#L349](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/supervisor.ex#L349) (Automatic shutdown section)
|
||||
|
||||
**What it does:** Supervisors support `:auto_shutdown` which terminates the supervisor when significant children exit. Options: `:any_significant` (first significant child exits → shutdown) or `:all_significant` (all significant children must exit → shutdown).
|
||||
|
||||
@@ -634,7 +634,7 @@ Supervisor.init(children, strategy: :one_for_one)
|
||||
|
||||
## Pattern 7: Task.async/await for Concurrent Value Computation
|
||||
|
||||
**Source:** `lib/elixir/lib/task.ex:1-20` and `lib/elixir/lib/task.ex:300-340`
|
||||
**Source:** [lib/elixir/lib/task.ex#L1](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/task.ex#L1) and [lib/elixir/lib/task.ex#L300](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/task.ex#L300)
|
||||
|
||||
**What it does:** `Task.async` spawns a linked, monitored process and returns a `%Task{}` struct. `Task.await` blocks until the result arrives or times out. This is the canonical pattern for "compute a value concurrently."
|
||||
|
||||
@@ -718,7 +718,7 @@ end
|
||||
|
||||
## Pattern 8: Task.Supervisor.async_nolink for Fault-Tolerant Task Execution
|
||||
|
||||
**Source:** `lib/elixir/lib/task/supervisor.ex:240-320` (async_nolink docs with GenServer example)
|
||||
**Source:** [lib/elixir/lib/task/supervisor.ex#L240](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/task/supervisor.ex#L240) (async_nolink docs with GenServer example)
|
||||
|
||||
**What it does:** Unlike `Task.async`, `async_nolink` spawns a task that is NOT linked to the caller. The caller monitors it and handles success/failure via `handle_info`. This prevents a task crash from killing the caller.
|
||||
|
||||
@@ -844,7 +844,7 @@ end
|
||||
|
||||
## Pattern 9: Task Supervisor as DynamicSupervisor Specialization
|
||||
|
||||
**Source:** `lib/elixir/lib/task/supervisor.ex:151-165` (start_link implementation)
|
||||
**Source:** [lib/elixir/lib/task/supervisor.ex#L151](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/task/supervisor.ex#L151) (start_link implementation)
|
||||
|
||||
**What it does:** `Task.Supervisor` is implemented directly on top of `DynamicSupervisor`. It stores default restart/shutdown settings in the process dictionary and delegates `init` to `DynamicSupervisor.init`.
|
||||
|
||||
@@ -936,7 +936,7 @@ DynamicSupervisor.start_child(MyApp.WorkerSupervisor, {MyApp.Worker, args})
|
||||
|
||||
## Pattern 10: Registry for Dynamic Process Naming and PubSub
|
||||
|
||||
**Source:** `lib/elixir/lib/registry.ex:1-70` (module docs), `lib/elixir/lib/registry.ex:250-270` (whereis_name via callbacks)
|
||||
**Source:** [lib/elixir/lib/registry.ex#L1](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/registry.ex#L1) (module docs), [lib/elixir/lib/registry.ex#L250](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/registry.ex#L250) (whereis_name via callbacks)
|
||||
|
||||
**What it does:** Registry provides two modes:
|
||||
- `:unique` keys — each key maps to exactly one process (name registry, process lookup)
|
||||
@@ -1053,7 +1053,7 @@ end
|
||||
|
||||
## Pattern 11: Shutdown Semantics — Graceful Termination
|
||||
|
||||
**Source:** `lib/elixir/lib/supervisor.ex:156-192` (Shutdown values section)
|
||||
**Source:** [lib/elixir/lib/supervisor.ex#L156](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/supervisor.ex#L156) (Shutdown values section)
|
||||
|
||||
**What it does:** Three shutdown modes:
|
||||
- `:brutal_kill` — immediate `Process.exit(child, :kill)`, no cleanup
|
||||
@@ -1155,7 +1155,7 @@ end
|
||||
|
||||
## Pattern 12: DynamicSupervisor Internal State — Struct with Restart Tracking
|
||||
|
||||
**Source:** `lib/elixir/lib/dynamic_supervisor.ex:165-178` (defstruct)
|
||||
**Source:** [lib/elixir/lib/dynamic_supervisor.ex#L165](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/dynamic_supervisor.ex#L165) (defstruct)
|
||||
|
||||
**What it does:** The DynamicSupervisor uses a struct for its GenServer state with explicit fields: `children` (map of pid → child spec), `restarts` (list of timestamps for rate limiting), and configuration fields.
|
||||
|
||||
@@ -1255,7 +1255,7 @@ end
|
||||
|
||||
## Pattern 13: Restart Logic with Exponential Backoff via `:try_again`
|
||||
|
||||
**Source:** `lib/elixir/lib/dynamic_supervisor.ex:710-758` (restart_child and related functions)
|
||||
**Source:** [lib/elixir/lib/dynamic_supervisor.ex#L710](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/dynamic_supervisor.ex#L710) (restart_child and related functions)
|
||||
|
||||
**What it does:** When a child fails to restart (start function returns error), DynamicSupervisor doesn't give up. It stores the child as `{:restarting, child}`, sends itself a `:"$gen_restart"` message, and retries later. This prevents the supervisor from blocking on a transiently failing child.
|
||||
|
||||
@@ -1382,7 +1382,7 @@ end
|
||||
|
||||
## Pattern 14: `$ancestors` and `$callers` — Process Lineage Tracking
|
||||
|
||||
**Source:** `lib/elixir/lib/task.ex:227-268` (Ancestor and Caller Tracking section)
|
||||
**Source:** [lib/elixir/lib/task.ex#L227](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/task.ex#L227) (Ancestor and Caller Tracking section)
|
||||
|
||||
**What it does:** Elixir uses two process dictionary keys for lineage:
|
||||
- `$ancestors` — the supervision hierarchy (who spawned/supervises this process)
|
||||
@@ -1495,7 +1495,7 @@ end
|
||||
|
||||
## Pattern 15: GenServer.reply/2 for Deferred Responses
|
||||
|
||||
**Source:** `lib/elixir/lib/gen_server.ex:620-640` (callback docs), `lib/elixir/lib/gen_server.ex:1328-1346` (reply/2 function)
|
||||
**Source:** [lib/elixir/lib/gen_server.ex#L620](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/gen_server.ex#L620) (callback docs), [lib/elixir/lib/gen_server.ex#L1328](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/gen_server.ex#L1328) (reply/2 function)
|
||||
|
||||
**What it does:** A `handle_call` can return `{:noreply, state}` without replying, then later call `GenServer.reply(from, response)` from any process. This decouples request receipt from response delivery.
|
||||
|
||||
@@ -1606,7 +1606,7 @@ end
|
||||
|
||||
## Pattern 16: Process.alias for Safe Request/Response
|
||||
|
||||
**Source:** `lib/elixir/lib/process.ex:32-95` (Aliases section)
|
||||
**Source:** [lib/elixir/lib/process.ex#L32](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/process.ex#L32) (Aliases section)
|
||||
|
||||
**What it does:** Process aliases (Erlang/OTP 24+) provide a deactivatable reference for receiving replies. After sending a request with an alias as the reply address, you can deactivate the alias if you no longer want the response — any messages sent to a deactivated alias are silently dropped.
|
||||
|
||||
@@ -1714,7 +1714,7 @@ end
|
||||
|
||||
## Pattern 17: Registry Partitioning Strategies
|
||||
|
||||
**Source:** `lib/elixir/lib/registry.ex:310-350` (start_link partitioning docs)
|
||||
**Source:** [lib/elixir/lib/registry.ex#L310](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/registry.ex#L310) (start_link partitioning docs)
|
||||
|
||||
**What it does:** Duplicate registries support two partitioning strategies:
|
||||
- `{:duplicate, :pid}` (default) — groups entries by the registering process's PID. Good for few keys with many entries (e.g., one PubSub topic with many subscribers).
|
||||
@@ -1812,7 +1812,7 @@ Registry.start_link(
|
||||
|
||||
## Pattern 18: `init/1` Return Values — The Full Spectrum
|
||||
|
||||
**Source:** `lib/elixir/lib/gen_server.ex:498-545` (init callback spec)
|
||||
**Source:** [lib/elixir/lib/gen_server.ex#L498](https://github.com/elixir-lang/elixir/blob/f4e1b34617ef92052b65781f18eae5b88a490098/lib/elixir/lib/gen_server.ex#L498) (init callback spec)
|
||||
|
||||
**What it does:** `init/1` supports five return values:
|
||||
- `{:ok, state}` — normal start
|
||||
@@ -1910,3 +1910,5 @@ end
|
||||
```
|
||||
|
||||
**Why:** `:ignore` means "this child intentionally should not run right now." `{:stop, reason}` means "this child tried to start and failed." Conflating the two hides real failures from your supervision tree.
|
||||
|
||||
<!-- PATTERN_COMPLETE -->
|
||||
|
||||
Reference in New Issue
Block a user