Skip to content

Commit 9831b24

Browse files
committed
docs(agents): add src/AGENTS.md with bootstrap wiring guide
1 parent d4efa67 commit 9831b24

1 file changed

Lines changed: 109 additions & 0 deletions

File tree

src/AGENTS.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# `src/` — Binary and Library Entry Points
2+
3+
This directory contains only the top-level wiring of the application: the binary entry points,
4+
the bootstrap sequence, and the dependency-injection container. All domain logic lives in
5+
`packages/`; this directory merely assembles and launches it.
6+
7+
## File Map
8+
9+
| Path | Purpose |
10+
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
11+
| `main.rs` | Binary entry point. Calls `app::run()`, waits for Ctrl-C, then cancels jobs and waits for graceful shutdown. |
12+
| `lib.rs` | Library crate root and crate-level documentation. Re-exports the public API used by integration tests and other binaries. |
13+
| `app.rs` | `run()` and `start()` — orchestrates the full startup sequence (setup → load data from DB → start jobs). |
14+
| `container.rs` | `AppContainer` — dependency-injection struct that holds `Arc`-wrapped instances of every per-layer container. |
15+
| `bootstrap/app.rs` | `setup()` — loads config, validates it, initializes logging and global services, builds `AppContainer`. |
16+
| `bootstrap/config.rs` | `initialize_configuration()` — reads config from the environment / file. |
17+
| `bootstrap/jobs/` | One module per service: each module exposes a starter function called from `app::start_jobs`. |
18+
| `bootstrap/jobs/manager.rs` | `JobManager` — collects `JoinHandle`s, owns the `CancellationToken`, and drives graceful shutdown. |
19+
| `bin/e2e_tests_runner.rs` | Binary that runs E2E tests by delegating to `src/console/ci/`. |
20+
| `bin/http_health_check.rs` | Minimal HTTP health-check binary used inside containers (avoids curl/wget dependency). |
21+
| `bin/profiling.rs` | Binary for Valgrind / kcachegrind profiling sessions. |
22+
| `console/` | Internal console apps (`ci/e2e`, `profiling`) used by the extra binaries above. |
23+
24+
## Bootstrap Flow
25+
26+
```text
27+
main()
28+
└─ app::run()
29+
├─ bootstrap::app::setup()
30+
│ ├─ bootstrap::config::initialize_configuration() ← reads TOML / env vars
31+
│ ├─ configuration.validate() ← panics on invalid config
32+
│ ├─ initialize_global_services() ← logging, crypto seed
33+
│ └─ AppContainer::initialize(&configuration) ← builds all containers
34+
35+
└─ app::start(&config, &app_container)
36+
├─ load_data_from_database() ← peer keys, whitelist, metrics
37+
└─ start_jobs()
38+
├─ start_swarm_coordination_registry_event_listener
39+
├─ start_tracker_core_event_listener
40+
├─ start_http_core_event_listener
41+
├─ start_udp_core_event_listener
42+
├─ start_udp_server_stats_event_listener
43+
├─ start_udp_server_banning_event_listener
44+
├─ start_the_udp_instances ← one job per configured UDP bind address
45+
├─ start_the_http_instances ← one job per configured HTTP bind address
46+
├─ start_torrent_cleanup
47+
├─ start_peers_inactivity_update
48+
├─ start_the_http_api
49+
└─ start_health_check_api ← always started
50+
```
51+
52+
Shutdown (`main`): receives `Ctrl-C` → calls `jobs.cancel()` (fires the `CancellationToken`) →
53+
waits up to 10 seconds for all `JoinHandle`s to complete.
54+
55+
## `AppContainer`
56+
57+
`AppContainer` (`container.rs`) is a plain struct — not a framework, not a trait object tree.
58+
It holds one `Arc<…Container>` per architectural layer:
59+
60+
| Field | Layer / Package |
61+
| ------------------------------------------------------------------------------------------------ | -------------------------------------------------------- |
62+
| `registar` | `server-lib` — tracks active server socket registrations |
63+
| `swarm_coordination_registry_container` | `swarm-coordination-registry` |
64+
| `tracker_core_container` | `tracker-core` |
65+
| `http_tracker_core_services` / `http_tracker_instance_containers` | `http-tracker-core` |
66+
| `udp_tracker_core_services` / `udp_tracker_server_container` / `udp_tracker_instance_containers` | `udp-tracker-core` / `udp-tracker-server` |
67+
68+
`AppContainer::initialize` is the only place where domain containers are constructed.
69+
Every `bootstrap/jobs/` starter receives an `&Arc<AppContainer>` and pulls out exactly what it
70+
needs — no globals, no lazy statics for domain objects.
71+
72+
## `JobManager`
73+
74+
`JobManager` (`bootstrap/jobs/manager.rs`) is a thin wrapper around a `Vec<Job>` (each `Job`
75+
holds a name + `JoinHandle<()>`) and a shared `CancellationToken`:
76+
77+
- `push(name, handle)` — registers a job.
78+
- `push_opt(name, handle)` — convenience for jobs that may be disabled.
79+
- `cancel()` — fires the token; all jobs that own a clone of it will observe cancellation.
80+
- `wait_for_all(timeout)` — joins all handles with a timeout, logging warnings for any that
81+
exceed it.
82+
83+
## Adding a New Service
84+
85+
When wiring a new server or background task, follow this checklist in order:
86+
87+
1. **Package** — add the new crate under `packages/` with the appropriate layer prefix.
88+
2. **Container field** — add an `Arc<NewServiceContainer>` field to `AppContainer` and
89+
initialize it inside `AppContainer::initialize`.
90+
3. **Job launcher** — create `src/bootstrap/jobs/new_service.rs` and register it in
91+
`src/bootstrap/jobs/mod.rs`.
92+
4. **Wire into `app::start_jobs`** — call the new starter function and push its handle to
93+
`job_manager`.
94+
5. **Graceful shutdown** — ensure the new service listens for the `CancellationToken` passed
95+
from `JobManager`.
96+
6. **Config guard** — if the service is optional, gate the starter behind the appropriate
97+
config field and use `push_opt`.
98+
99+
## Key Rules for This Directory
100+
101+
- **No domain logic here.** This directory is pure wiring. Business rules belong in `packages/`.
102+
- **No globals for domain objects.** All state flows through `AppContainer`.
103+
- **Startup errors panic.** `bootstrap::app::setup()` panics on invalid config or a bad crypto
104+
seed — this is intentional (fail fast before binding ports).
105+
- **Health check always starts.** The health-check API job is unconditional — do not gate it
106+
behind a config flag.
107+
- **`lib.rs` is the integration-test surface.** Integration tests import
108+
`torrust_tracker_lib::…`. Keep the public API in `lib.rs` stable; avoid leaking internal
109+
bootstrap details.

0 commit comments

Comments
 (0)