fix(swarm-queue-client): export chain, and use it where anyhow used to
Review catch: `anyhow::Error`'s Display special-cases `f.alternate()` to
walk the source chain; thiserror's derive does not, so `{e:#}` and `{e}`
render identically for the new error type. Every call site that held an
`anyhow::Error`, formatted it with `{:#}`, and now holds this crate's
error kept compiling, kept looking right, and silently dropped the cause.
`chain()` was written for exactly this and then left private, applied only
to the auth callback I happened to be editing. Its own doc comment argues
that dropping the source chain is wrong, which made it the one thing in
the PR that should not have had a scope of one.
The controller's "swarm queue unreachable" warning is the site this fixes
here; the stacked PR fixes the two boot-warning banners, which matter more
still — one-shot, no retry, and they leak until restart.
This commit is contained in:
parent
d71222c206
commit
79bc198165
2 changed files with 21 additions and 7 deletions
|
|
@ -318,7 +318,13 @@ async fn main() -> Result<()> {
|
|||
)))
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!(error = format!("{e:#}"), "swarm queue unreachable");
|
||||
// `chain`, not `{:#}`: this is the queue client's own
|
||||
// error type, and thiserror's Display ignores the
|
||||
// alternate flag — the source would be dropped silently.
|
||||
tracing::warn!(
|
||||
error = swarm_queue_client::chain(&e),
|
||||
"swarm queue unreachable"
|
||||
);
|
||||
None
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -88,12 +88,20 @@ pub enum Error {
|
|||
|
||||
/// Render an error and its source chain on one line.
|
||||
///
|
||||
/// The auth callback below hands `async-nats` a *string*, so a `Display`
|
||||
/// that stopped at the top message would drop the cause — which is the
|
||||
/// half that says why the mint failed. `anyhow`'s `{:#}` did this for
|
||||
/// free; a library owes its callers the same detail without owing them
|
||||
/// anyhow.
|
||||
fn chain(error: &dyn std::error::Error) -> String {
|
||||
/// **Use this instead of `{:#}` anywhere an [`Error`] is rendered without
|
||||
/// first being `?`-converted into an `anyhow::Error`.** `anyhow`'s
|
||||
/// `Display` special-cases `f.alternate()` to walk the source chain;
|
||||
/// `thiserror`'s derive does not, so `{e:#}` and `{e}` render
|
||||
/// identically for this type. A call site that formatted an
|
||||
/// `anyhow::Error` with `{:#}` and now holds an [`Error`] therefore keeps
|
||||
/// compiling, keeps looking right, and silently drops the cause — which
|
||||
/// is the half that says *why*, and is exactly what a one-shot boot
|
||||
/// warning with no retry needs most.
|
||||
///
|
||||
/// Public for that reason: the fix cannot live only inside this crate's
|
||||
/// own auth callback while the callers it was written for reach for
|
||||
/// `{:#}` and get nothing.
|
||||
pub fn chain(error: &dyn std::error::Error) -> String {
|
||||
let mut rendered = error.to_string();
|
||||
let mut source = error.source();
|
||||
while let Some(cause) = source {
|
||||
|
|
|
|||
Loading…
Reference in a new issue