-
Notifications
You must be signed in to change notification settings - Fork 14
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
fix(commands): return error if check fails #224
base: main
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files
|
I'll look through it tomorrow. 👍🏽 |
pub enum CheckErrorLevel { | ||
/// A warning: Something is strange and should be corrected, but repository integrity is not affected. | ||
Warn, | ||
/// An erro: Something in the repository is not as it should be. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// An erro: Something in the repository is not as it should be. | |
/// An error: Something in the repository is not as it should be. |
#[derive(Debug)] | ||
/// `CheckResults` is a list of errors encountered during the check. | ||
pub struct CheckResults { | ||
/// The list of errors with severity level. | ||
pub errors: Vec<(CheckErrorLevel, CheckError)>, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering if we could replace these with: https://crates.io/crates/lazy_errors
Didn't use it, but it sounded interesting on Reddit last week: https://www.reddit.com/r/rust/comments/1ddi1nb/i_published_my_first_crate_lazy_errors/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looks still relevant to me, lazy_errors looks actually really good for collecting multiple errors like CheckResults does but looks more ergonomic to me at first look.
// TODO: Make concurrency (20) customizable | ||
check_cache_files(20, cache, raw_be, file_type, &p)?; | ||
self.check_cache_files(20, cache, raw_be, file_type, &p)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure, if that could be just a field in CheckOptions
? or maybe another struct ParallelismOptions
composed into CheckOptions
that we can use in rustic_core.
// TODO: Make concurrency (5) customizable | ||
check_cache_files(5, cache, raw_be, FileType::Pack, &p)?; | ||
self.check_cache_files(5, cache, raw_be, FileType::Pack, &p)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, maybe ParallelismOptions
could be useful here as well?
Err(err) => error!("Error reading pack {id} : {err}",), | ||
Err(err) => self.add_error(CheckError::ErrorReadingPack { | ||
id, | ||
err: Box::new(err), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would call it source
so it's more clear also because thiserror
infers from it
} | ||
self.errors | ||
.lock() | ||
.unwrap() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would at least prefer an expect
here
|
||
#[non_exhaustive] | ||
#[derive(Error, Debug, Display)] | ||
pub enum CheckError { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't that also be convertable to RusticError?
#[derive(Debug)] | ||
/// `CheckResults` is a list of errors encountered during the check. | ||
pub struct CheckResults { | ||
/// The list of errors with severity level. | ||
pub errors: Vec<(CheckErrorLevel, CheckError)>, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looks still relevant to me, lazy_errors looks actually really good for collecting multiple errors like CheckResults does but looks more ergonomic to me at first look.
After looking through it, I understand better now, what I found confusing about it, back in May. It's really because it introduces a special way to handle errors only for The For collecting the errors in a method/function we could use
But this topic is definitely something we should talk about to find a good approach. |
In principle I like the ides of
|
I sketched out an idea, to fix the pain points you mentioned in a more generic way, than introducing special error handling/collection for |
I think the main question here is: |
I would wait, I don't think (no offence really, we are doing a lot here) this should be merged as it is. We are introducing new errors here (CheckError), etc. We should just focus on this error handling topic, after the next Also, the design implies, we implement |
Let's rather do it right one time with a bit more effort now, than doing it more than once, just to be quick and dirty. 😅 |
For this situation, can you give an example, because this is worth to explore why it is like that. There could be many reasons for it, e.g. architectural problems, prolonged error handling, instead of doing it locally, etc. When it comes to collecting errors in a thread, we can go for a channel and handle it in the main thread. |
…ne, repair, key, and restore (#317) I saw in #224 that `CheckOptions::run()` has been moved to type `CheckResultsCollector`. In other commands we actually have functions, not associated to any type, that take their options as parameters. I applied this here to check, prune, repair, key, and restore as well. Because I think it reduces coupling and increases testability. The idea behind having these standalone functions is, that check, prune, repair, key, and restore are not run on their options (as a method of e.g. `CheckOptions`), but rather take parameters, where one is the e.g. `CheckOption` itself. In principle: methods that implement commands don't operate on their own options and have side effects on other types - options are passed into functions as parameters. Furthermore, a `check()` on `CheckOptions` sounds if it validates these options itself, rather than being run on an external type. I think from that POV it also makes sense to have such freestanding functions as entry point to our commands in `rustic_core`. --------- Signed-off-by: simonsan <[email protected]>
An example is There are errors like not being able to list snapshots which will cause this command to fail. But each individual snapshot may fail either to load from backend or to decrypt (e.g. data corruption). Currently, this functions fails if any snapshot fails to load+decrypt. This means if we have a corrupt snapshot file, the repository can be basically no longer used until this is fixed. We however may want to introduce resiliency: It is e.g. very nasty if the whole repository is not accessible just because that old and now unimportant snapshotfile has an issue. If we introduce this, then the command would return the successful loaded snapshots and a list of failed snapshots with the error(s) - and we would at least need to indicate that something went wrong by not sending a 0 return code in some cases... |
I would imagine it like this somehow (draft): So we have a , and we reserve the But in the end, it's the question of why we want to return a list of the non-working snapshots and not just log an error there. What value has the information for the caller, that there are broken snapshots it cannot be operated on? We just don't want it to fail, right? If we return that |
closes #222