Graph the artwork thrown out, not the artwork kept (#198)

The sweep trims the cache to its limit, so the kept bytes it reports are the
limit every time once the cache has filled: the panel was two lines flat at
500 MiB. A counter of images thrown out says whether the limit is too small.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-11 20:15:11 +00:00
parent 12fadbd0f8
commit f032d50ed3
5 changed files with 13 additions and 4 deletions

View File

@@ -84,7 +84,8 @@ from 2026-10-11 15:15 UTC. All gauges:
| `ipx_event_queue`, `ipx_events_missed_total` | live updates unread by some listener; counter of those dropped for one that fell behind |
| `ipx_deadair_backlog`, `ipx_deadair_busy_seconds` | files of shows with DeadAir on not yet looked at (episodes everyone heard through stay counted); how long it has been on its file |
| `ipx_feed_retries` | feeds waiting to retry a failed name lookup |
| `ipx_art_cache_bytes`, `ipx_art_cache_limit_bytes` | artwork kept, as of the last sweep, and the most kept |
| `ipx_art_cache_bytes`, `ipx_art_cache_limit_bytes` | artwork kept, as of the last sweep, and the most kept: kept sits at the limit by design |
| `ipx_art_trimmed_total` | counter: images the sweep threw out to stay under the limit; many at every sweep means the limit is too small |
| `ipx_feeds`, `ipx_downloads_pending`, `ipx_files_downloaded` | the library, as the healthcheck last counted it (every 30 s) |
## The checks

View File

@@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- With `[web] metrics_bind` set, `/metrics` gives Prometheus, on a thread and port of its own, what the daemon holds between requests: database connections in use against the pool's size, commands waiting for the worker, live-update listeners, the runtime's tasks, memory and open files. So are the worker's job and how long it has run, jobs done and their time by kind, when a scan last finished, web requests, feed fetches and downloads in progress, download speed, live updates queued and missed, DeadAir's backlog and the file it is on, feeds waiting to retry, the artwork kept and the library's counts. The iPX dashboard graphs them in a Daemon row (#194, #195).
- With `[web] metrics_bind` set, `/metrics` gives Prometheus, on a thread and port of its own, what the daemon holds between requests: database connections in use against the pool's size, commands waiting for the worker, live-update listeners, the runtime's tasks, memory and open files. So are the worker's job and how long it has run, jobs done and their time by kind, when a scan last finished, web requests, feed fetches and downloads in progress, download speed, live updates queued and missed, DeadAir's backlog and the file it is on, feeds waiting to retry, the artwork kept and the library's counts. So is how much artwork the sweep throws out to stay under its limit. The iPX dashboard graphs them in a Daemon row (#194, #195, #198).
- The page reports its errors, the player's, how long play takes to start and how long it stalls to the server's log, and the requests one tap sets off share a trace, the playlist, audio and saved place of what it played included (#190, #192).
- Saving an episode from a show with DeadAir on saves it without its dead air, at your breathing room (#186).
- Choose the pause DeadAir leaves where it cuts a silence, from 0.2 to 0.5 seconds, for each show in its settings, as its breathing room, on a slider from brisk to relaxed. It is 0.3 seconds unless you change it, up from 0.2, which made speech sound rushed (#182, #183).

View File

@@ -187,8 +187,10 @@ ts("Backlogs", [prom('max(ipx_deadair_backlog{job="ipx"})', legend="DeadAir to l
y += 8
ts("DeadAir on a file", [prom('max(ipx_deadair_busy_seconds{job="ipx"})', legend="for")], 0, w=12, unit="s",
desc="How long DeadAir has been on the file it is analysing; a few seconds each.")
ts("Artwork kept", [prom('max(ipx_art_cache_bytes{job="ipx"})', legend="kept"),
prom('max(ipx_art_cache_limit_bytes{job="ipx"})', ref="B", legend="the most kept")], 12, w=12, unit="bytes")
ts("Artwork thrown out", [prom('sum(increase(ipx_art_trimmed_total{job="ipx"}[$__rate_interval]))', legend="images")],
12, w=12, bars=True,
desc="What is kept sits at its limit (500 MiB unless changed), since each sweep trims the least recently used to fit. "
"Many thrown out at every sweep means the limit is too small and artwork is fetched again.")
y += 8
# ---- Traces

View File

@@ -98,6 +98,7 @@ pub fn trim(dir: &Path, limit: u64) -> usize {
}
}
crate::metrics::STATS.art_cache_bytes.store(total, std::sync::atomic::Ordering::Relaxed);
crate::metrics::STATS.art_trimmed.fetch_add(gone as u64, std::sync::atomic::Ordering::Relaxed);
gone
}

View File

@@ -30,6 +30,9 @@ pub struct Stats {
/// When DeadAir started on the file it is on, Unix seconds; 0 when it is on none.
pub deadair_busy_since: AtomicI64,
pub art_cache_bytes: AtomicU64,
/// Images the sweep threw out to keep under the limit: kept bytes sit at the limit by design,
/// so this is what says whether the limit is too small.
pub art_trimmed: AtomicU64,
/// The library as the healthcheck last counted it, every 30 s; -1 until it has.
pub feeds: AtomicI64,
pub pending: AtomicI64,
@@ -52,6 +55,7 @@ impl Stats {
deadair_backlog: AtomicI64::new(0),
deadair_busy_since: AtomicI64::new(0),
art_cache_bytes: AtomicU64::new(0),
art_trimmed: AtomicU64::new(0),
feeds: AtomicI64::new(-1),
pending: AtomicI64::new(-1),
downloaded: AtomicI64::new(-1),
@@ -205,6 +209,7 @@ fn work(out: &mut String, st: &Stats, event_queue: usize, retries: usize, art_li
gauge(out, "ipx_feed_retries", "Feeds waiting to try a failed name lookup again.", &[("", retries as f64)]);
gauge(out, "ipx_art_cache_bytes", "Artwork kept on disk, as of the last sweep.", &[("", st.art_cache_bytes.load(Relaxed) as f64)]);
gauge(out, "ipx_art_cache_limit_bytes", "The most artwork kept.", &[("", art_limit as f64)]);
counter(out, "ipx_art_trimmed_total", "Images thrown out to keep the artwork under its limit.", &[("", st.art_trimmed.load(Relaxed) as f64)]);
for (name, help, v) in [
("ipx_feeds", "Feeds in the catalogue, as the healthcheck last counted.", &st.feeds),
("ipx_downloads_pending", "Files a scan will download on its own, as the healthcheck last counted.", &st.pending),