Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start Refining Errors #686

Merged
merged 9 commits into from
Nov 1, 2021
Merged

Start Refining Errors #686

merged 9 commits into from
Nov 1, 2021

Conversation

kazk
Copy link
Member

@kazk kazk commented Oct 30, 2021

I wanted to add "Refine Errors" (opened #688) to our roadmap, so I tried a bit to see how we can tackle this. Any feedback is appreciated.

Remove impl From<T> for kube::Error

Require explicitly mapping errors.
This commit shows how much we need to mentally process while reading the code (maintenance cost), and how badly grouped they are (usability issue).
Removing impl From forces us to attach context, and this is a good thing. It's verbose right now, but that's because we need to break them down.

As an example, I got rid of kube_core::Error. Parsing group version no longer has an error variant HttpError.

thiserror vs snafu

As I mentioned in thiserror vs snafu discussion, the huge kube::Error is a problem I'd like us to start fixing. I've been using both thiserror and snafu, and I think using thiserror without #[from], and gradually breaking errors down is probably the best approach for kube. While I think snafu help us initially to think of errors in a more scalable way, it's not necessary to implement the pattern. Also, we probably can't do SNAFU way until we finish breaking them down cleanly anyway, and the features to prevent misuse will get in the way (e.g., private context selectors by default). So, I don't think it's worth some downsides.

Stability

thiserror is stable (v1). snafu is still evolving. 0.7 will add Snafu suffix to generated context selectors. Tuple variants are not well-supported? (I haven't used tuple variants with snafu, so I don't know the details).

Popularity

thiserror v1 is used by 9,491 public crates. snafu 0.6 is used by 270. snafu is extra dependency for many.

Features

snafu provides some syntactic sugars, but I don't think it adds that much value. Avoiding #[from] and using the usual Result::map_err feels similar enough, especially as we break the errors down.

let mut file = File::open(path).context(OpenFileSnafu { path })?;
let mut file = File::open(path).map_err(|e| Error::OpenFile(e, path.to_owned()))?;
let mut file = File::open(path).map_err(|source| Error::OpenFile { source, path: path.into() })?;

action().context(ActionSnafu)?;
action().map_err(Error::Action)?;

One feature snafu optionally provides that thiserror doesn't, is backtrace in stable, but this requires the end users to depend on snafu and enable the backtrace feature. There are error reporter crates to do this until backtrace become stable.

Unless I missed something significant, I think we should go with thiserror without #[from].

@kazk kazk marked this pull request as draft October 30, 2021 05:55
@kazk kazk requested review from clux and nightkr October 30, 2021 06:38
@nightkr
Copy link
Member

nightkr commented Oct 30, 2021

Big 👍 on the overall idea.

I've been using both thiserror and snafu, and I think using thiserror without #[from], and gradually breaking errors down is probably the best approach for kube.

That makes sense to me.

While I think snafu help us initially to think of errors in a more scalable way, it's not necessary to implement the pattern.

Definitely, it's all just syntax sugar in the end.

Also, we probably can't do SNAFU way until we finish breaking them down cleanly anyway, and the features to prevent misuse will get in the way (e.g., private context selectors by default). So, I don't think it's worth some downsides.

While it'd be nice to only depend on one of them in the end, we don't need to go all-in from the start. Neither of them are visible in the public API, and they interoperate just fine (aside from SNAFU's backtraces).

thiserror is stable (v1). snafu is still evolving. 0.7 will add Snafu suffix to generated context selectors.

I'm not looking forward to that upgrade, but there's also no huge rush. We're not holding anyone else back from upgrading since we're only exposing the std::error::Error instance anyway.

Tuple variants are not well-supported? (I haven't used tuple variants with snafu, so I don't know the details).

To be honest I kind of dislike tuple variants anyway, since they become quite messy as soon as you want to add any extra context to the errors, as demonstrated by your file example. I'd feel much more comfortable pattern-matching Error::OpenFile { source: io::Error, path: PathBuf } than Error::OpenFile(io::Error, Path) (and this is a relatively tame example since all context has types that more or less indicate what everything is..).

@nightkr
Copy link
Member

nightkr commented Oct 30, 2021

To be clear: even if I might personally prefer going full SNAFU, (IMO) modularized thiserror is still a vast improvement over what we currently have.

@clux
Copy link
Member

clux commented Oct 30, 2021

Yeah, I like this a lot as well. Gets us going on refining.

thiserror vs snafu

This justification is good. The popularity of thiserror has exploded compared to snafu which is declining (and we are the top listed depender). Thiserror also have dtolnay behind it as a maintainer who is making frequent non-breaking patch releases (.30 now).

Regardless of how pointless a popularity contest may seem, pretty much everyone knows how to wrangle thiserror and that is also nice from a fresh contributor POV.

@kazk
Copy link
Member Author

kazk commented Oct 31, 2021

Cool, I'll open a tracking issue with a summary and task list.

To be honest I kind of dislike tuple variants anyway, since they become quite messy as soon as you want to add any extra context to the errors, as demonstrated by your file example. I'd feel much more comfortable pattern-matching Error::OpenFile { source: io::Error, path: PathBuf } than Error::OpenFile(io::Error, Path) (and this is a relatively tame example since all context has types that more or less indicate what everything is..).

Yeah, we should avoid tuple if it makes the error difficult to use. We should decide what's best for each error, and thiserror doesn't limit us.

@kazk kazk mentioned this pull request Oct 31, 2021
19 tasks
@kazk kazk changed the title Refine Errors Start Refining Errors Oct 31, 2021
@kazk kazk force-pushed the refine-errors branch 2 times, most recently from c2f1faa to 8931e04 Compare October 31, 2021 06:22
kube-runtime/src/controller/mod.rs Show resolved Hide resolved
kube-runtime/src/wait.rs Show resolved Hide resolved
@kazk kazk marked this pull request as ready for review October 31, 2021 06:43
Require explicitly mapping errors.
This commit shows how much we need to mentally process while reading the
code (maintenance cost), and how badly grouped they are (usability issue).
Removing `impl From` forces us to attach context.

Signed-off-by: kazk <kazk.dev@gmail.com>
Signed-off-by: kazk <kazk.dev@gmail.com>
Signed-off-by: kazk <kazk.dev@gmail.com>
Signed-off-by: kazk <kazk.dev@gmail.com>
Signed-off-by: kazk <kazk.dev@gmail.com>
Signed-off-by: kazk <kazk.dev@gmail.com>
Signed-off-by: kazk <kazk.dev@gmail.com>
Signed-off-by: kazk <kazk.dev@gmail.com>
Copy link
Member

@clux clux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great to me! Generally just minor nits. But but have one question left on our approach w.r.t. #515 .

@@ -26,7 +26,7 @@ use kube_core::{
/// ```no_run
/// use kube::{Client, api::{Api, DynamicObject}, discovery, ResourceExt};
/// #[tokio::main]
/// async fn main() -> Result<(), kube::Error> {
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
Copy link
Member

@clux clux Oct 31, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As an aside here; I think we probably should move our docs to use an async fn wrapper here ala https://github.com/kube-rs/kube-rs/blob/master/kube-runtime/src/events.rs#L134 to reduce the docs cruft everywhere (not necessary in this PR)

kube-client/src/error.rs Show resolved Hide resolved
kube-runtime/src/controller/mod.rs Show resolved Hide resolved
examples/configmapgen_controller.rs Outdated Show resolved Hide resolved
Signed-off-by: kazk <kazk.dev@gmail.com>
@kazk kazk merged commit 120d000 into kube-rs:master Nov 1, 2021
@kazk kazk deleted the refine-errors branch November 1, 2021 00:19
@clux clux added the errors error handling or error ergonomics label Nov 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
errors error handling or error ergonomics
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants