Initial commit -- did OMO do a good job?
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
Task: todo 18 – news-server axum wiring (/healthz, /metrics, scheduler, main.rs)
|
||||
Date: 2026-09-01
|
||||
|
||||
Files created/modified:
|
||||
- crates/news-server/src/main.rs (rewritten, thin binary + run_once/start_background_loops)
|
||||
- crates/news-server/src/bin_support.rs (new runtime/setup helpers)
|
||||
- crates/news-server/src/lib.rs (register health + scheduler modules)
|
||||
- crates/news-server/src/health.rs (new /healthz + /metrics + Metrics)
|
||||
- crates/news-server/src/scheduler.rs (new module root)
|
||||
- crates/news-server/src/scheduler/cycle.rs (new PollCycleError + poll_source_once)
|
||||
- crates/news-server/src/scheduler/loops.rs (new per-source/digest/pruning loops + tests)
|
||||
- crates/news-server/src/scheduler/metrics.rs (new decision metric recording)
|
||||
- crates/news-store/src/items.rs (delete_fetched_before + get helpers)
|
||||
- crates/news-server/src/notify/digest.rs (return bool flag, no tests moved)
|
||||
- crates/news-server/src/notify/digest/tests.rs (new split test module)
|
||||
- Cargo.toml (workspace prometheus dependency)
|
||||
- crates/news-server/Cargo.toml (crate prometheus dependency)
|
||||
|
||||
Verification commands
|
||||
---------------------
|
||||
|
||||
1. Formatting
|
||||
$ cargo fmt --all --check
|
||||
Result: clean
|
||||
|
||||
2. Clippy
|
||||
$ cargo clippy --workspace --all-targets -- -D warnings
|
||||
Result: clean
|
||||
|
||||
3. Workspace tests
|
||||
$ cargo test --workspace
|
||||
Result: passed (79 tests total)
|
||||
- news-cli: 2 passed
|
||||
- news-core: 18 passed
|
||||
- news-ingest: 4 passed
|
||||
- news-server: 33 passed
|
||||
- news-store: 22 passed
|
||||
|
||||
4. File size (scc pure LOC, tests excluded where noted)
|
||||
$ scc --no-cocomo --no-complexity --by-file \
|
||||
crates/news-server/src/main.rs \
|
||||
crates/news-server/src/bin_support.rs \
|
||||
crates/news-server/src/health.rs \
|
||||
crates/news-server/src/scheduler.rs \
|
||||
crates/news-server/src/scheduler/cycle.rs \
|
||||
crates/news-server/src/scheduler/loops.rs \
|
||||
crates/news-server/src/scheduler/metrics.rs \
|
||||
crates/news-server/src/notify/digest.rs \
|
||||
crates/news-server/src/notify/digest/tests.rs \
|
||||
crates/news-store/src/items.rs
|
||||
Result: every production module is under the 250 pure-LOC ceiling
|
||||
- main.rs: 154
|
||||
- bin_support.rs: 194
|
||||
- health.rs: 152
|
||||
- scheduler.rs: 8
|
||||
- scheduler/cycle.rs: 182
|
||||
- scheduler/loops.rs: 246
|
||||
- scheduler/metrics.rs: 37
|
||||
- notify/digest.rs: 170 (tests moved to digest/tests.rs)
|
||||
- news-store/src/items.rs: 228
|
||||
|
||||
5. Live server QA
|
||||
Built binary first to separate compile time from runtime.
|
||||
$ cargo build --bin news-server
|
||||
$ NEWS_PORT=3999 NEWS_DB_PATH=/tmp/news_qa.db ./target/debug/news-server &
|
||||
$ sleep 3
|
||||
$ curl -s http://127.0.0.1:3999/healthz
|
||||
{"db":"ok","status":"ok"}
|
||||
$ curl -s http://127.0.0.1:3999/metrics | head -5
|
||||
# HELP news_scrape_duration_seconds Wall time for one source poll cycle
|
||||
# TYPE news_scrape_duration_seconds histogram
|
||||
news_scrape_duration_seconds_bucket{le="0.005"} 0
|
||||
...
|
||||
Result: /healthz returned HTTP 200 JSON, /metrics returned HTTP 200 Prometheus text.
|
||||
|
||||
6. Dry-run once QA
|
||||
$ NEWS_DB_PATH=/tmp/news_dryrun.db ./target/debug/news-server --dry-run --once
|
||||
Result: exit 0, printed decision rows, no real ntfy calls.
|
||||
Sample output:
|
||||
Ogwumike has 23 points and 12 rebounds as Sparks beat Storm… 2.400 0.000 50.000 Suppress:BelowThreshold
|
||||
... (many more Suppress:BelowThreshold rows)
|
||||
exit_code=0
|
||||
|
||||
Implementation notes
|
||||
--------------------
|
||||
- Metrics exposed:
|
||||
- news_poll_total{source}
|
||||
- news_notify_total{lane="normal"|"bypass"|"digest"}
|
||||
- news_suppress_total{reason}
|
||||
- news_scrape_duration_seconds histogram
|
||||
- Per-source scheduler loop respects source.poll_interval_secs, spawns each
|
||||
source in its own task, and applies exponential backoff only to the source
|
||||
that returned RateLimited.
|
||||
- Daily pruning job runs at 03:00 America/Louisville via duration_until_03_00
|
||||
and deletes raw_items (and orphan cluster_members) older than 90 days.
|
||||
- main.rs now delegates runtime construction to bin_support::build_runtime and
|
||||
keeps orchestration helpers (run_once, start_background_loops) in main.rs so
|
||||
both files stay under the 250 LOC ceiling.
|
||||
- digest.rs tests were split into digest/tests.rs to keep the core module small.
|
||||
|
||||
Known divergences from plan wording
|
||||
-----------------------------------
|
||||
- The plan acceptance criteria names the tests `main::healthz_returns_200_...`
|
||||
and `main::pruning_job_deletes_...`. The actual tests live at
|
||||
`health::tests::healthz_returns_200_when_db_reachable` and
|
||||
`scheduler::loops::tests::pruning_job_deletes_items_older_than_90_days_keeps_newer`.
|
||||
Behavior and coverage match the acceptance criteria exactly.
|
||||
- Default config is built into bin_support::default_config() when
|
||||
/config/config.toml is absent, so `cargo run` works outside a container
|
||||
without an explicit config file.
|
||||
Reference in New Issue
Block a user