Closed
Description
It's fairly common practice for us to create a set of metrics from a metric family given a set of labels, and store them for later use. However, this can cause a deadlock when Family::get_or_create
is called multiple times on the same instance within the same statement:
struct Metrics {
inbound: Counter,
outbound: Counter,
}
let family = Family::<Vec<(String, String)>, Counter>::default();
Metrics {
inbound: family.get_or_create(&vec!["dir", "inbound"]).clone(),
outbound: family.get_or_create(&vec!["dir", "outbound"]).clone(), // deadlocks
}
This is due to the RwLockReadGuard
returned by each call to Family::get_or_create
being temporaries that are not dropped until the end of the statement.
The user-facing solution is to create separate bindings for each metric:
// ...
let inbound - family.get_or_create(&vec!["dir", "inbound"]).clone();
let outbound = family.get_or_create(&vec!["dir", "outbound"]).clone(); // no deadlock
Metrics { inbound, outbound }
However, this is a footgun that can be pretty tricky to debug. Is there an alternative API here that would work, perhaps just returning the metric directly instead of a mutex guard?
Metadata
Metadata
Assignees
Labels
No labels