A list's trace says which list it was (#287)

The prod check of 2026-10-19 found /api/entries requests of 0.5-0.8 s
overnight beside others of 80-100 ms on an idle host, the time all in
entries_in, and nothing in the trace said which filter, sort or page
they were. The step now carries them, and whether a search, not its words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-19 14:05:50 +00:00
parent 187729a278
commit 6daab6989e
3 changed files with 16 additions and 9 deletions

View File

@@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- A show from an OPML subscription or a Patreon creator can be kept: `kept` on `PATCH /api/feeds/{id}` and in the feed list. When the OPML drops a kept show, or you leave the OPML, it stays on your list as a feed of its own (#280).
- `/metrics` counts Signals: items judged and fitting, calls to Jev by how they ended, the time they took and the tokens TypeSafe counted, time since the judge's last pass, and keys refused; a failed call to Jev shows as a failed trace (#270, #275).
- An admin setting for how many days back a new Signal reads (#276).
- A list's trace says which filter, sort and page it was asked for, and whether a search, so a slow list can be told from the others (#287).
- `/metrics` breaks Signals' items, fits and TypeSafe tokens out by person and by whose key paid, so the server's bill can be split (#278).
- An admin setting, Signals for everyone on the server's TypeSafe key, so the server pays for Jev instead of each person (#271).

View File

@@ -1502,17 +1502,23 @@ async fn entry_page(
let order =
crate::db::order_sql(page.sort.as_deref().unwrap_or("published"), page.dir.as_deref().unwrap_or("desc"));
let limit = page.limit.clamp(1, 200);
// Which list, so a slow one's trace says what was asked of it (#287). The search's words stay
// out: they are the reader's own.
let in_list = tracing::info_span!(
"step",
of = "entries_in",
filter = page.filter.as_deref().unwrap_or("all"),
sort = page.sort.as_deref().unwrap_or("published"),
dir = page.dir.as_deref().unwrap_or("desc"),
offset = page.offset,
limit,
search = search.is_some(),
);
let mut rows = match signal {
Some(id) => {
db.signal_entries(user_id, id, filter, search, page.offset, limit, &order)
.instrument(step("entries_in"))
.await?
}
None => {
db.entries_of(user_id, feeds, filter, search, page.offset, limit, &order)
.instrument(step("entries_in"))
.await?
db.signal_entries(user_id, id, filter, search, page.offset, limit, &order).instrument(in_list).await?
}
None => db.entries_of(user_id, feeds, filter, search, page.offset, limit, &order).instrument(in_list).await?,
};
step("sanitize").in_scope(|| {
let mut sanitizer = feed_sanitizer();