Good point on holding across awaits, I don't need to, the lookup returns a small Copy struct.
That p99 point is the sort of thing I wouldn't have caught in a benchmark of averages. Thanks.
One boring thing: confirm your April migration kept 301s from every old product URL. If a page lost its history it's effectively a brand new URL competing with nothing to its name, and thin new URLs are exactly what gets parked in that report.
If you genuinely need Rc, tokio::task::spawn_local on a LocalSet works and keeps everything on one thread. It's a real option for per-connection actors, just be aware you've now decided that task never migrates, which is fine until you want it to be.
Ran that. 40 pages, 14 clusters, and four of those clusters are just location variants of the same service.
One thing that trips people: if the predicate itself borrows something with a shorter life than self, no signature will save you and you genuinely do need to restructure. Passing the filter criteria in by value, as above, is what makes the simple signature possible.
Position 6 for both might not be cannibalisation at all, it might just be that neither is good enough to be top 3 and they're taking turns at the bottom of the pile. Worth being honest about that before spending a weekend on redirects.
It's mostly hours, but the hours count for more if you read the error message properly instead of scanning for the line number. They tell you which borrow, where it started and where it ends. I ignored the middle of those messages for my whole first month.