-
Notifications
You must be signed in to change notification settings - Fork 182
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
Specialize errors #1081
Specialize errors #1081
Conversation
c511d9d
to
8a21f78
Compare
8a21f78
to
2f83fc1
Compare
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.
Thank you for your PR!
It would be good to discuss refactor ideas in issue/discussions first to avoid reviews with such big number of comments :).
@@ -149,15 +136,16 @@ impl Client { | |||
/// # Ok(()) | |||
/// # } | |||
/// ``` | |||
pub async fn publish(&self, subject: String, payload: Bytes) -> Result<(), PublishError> { | |||
pub async fn publish(&self, subject: String, payload: Bytes) -> Result<(), RequestError> { |
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.
One of the reasons for concrete errors was to only surface those ones, that are meaningful for the user.
After this change, we get irrelevant and maybe even misleading variants:
match client.publish("foo".into(), "data".into()).await {
Ok(_) => (),
Err(err) => match err.kind() {
RequestErrorKind::TimedOut => todo!(),
RequestErrorKind::NoResponders => todo!(),
RequestErrorKind::Other => todo!(),
RequestErrorKind::SendFlushFailed => todo!(),
RequestErrorKind::FlushFailed => todo!(),
RequestErrorKind::PublishingFailed => todo!(),
RequestErrorKind::SubscriptionFailed => todo!(),
RequestErrorKind::UnsubscriptionFailed => todo!(),
},
}
We should stick to PublishError
having variants valid only for Publish.
Publish never subscribes, not reach NoResponders etc.
@@ -407,7 +398,7 @@ impl Client { | |||
/// # Ok(()) | |||
/// # } | |||
/// ``` | |||
pub async fn subscribe(&self, subject: String) -> Result<Subscriber, SubscribeError> { | |||
pub async fn subscribe(&self, subject: String) -> Result<Subscriber, RequestError> { |
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.
The same applies here.
Subscribe kind should not expose most of the variants in RequestError
.
After all, Request
is more or less subscribe
+ publish
.
@@ -473,16 +466,16 @@ impl Client { | |||
/// # Ok(()) | |||
/// # } | |||
/// ``` | |||
pub async fn flush(&self) -> Result<(), FlushError> { |
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.
And the same applies here.
@@ -44,6 +45,23 @@ use serde::{Deserialize, Serialize}; | |||
/// # } | |||
/// ``` | |||
|
|||
#[derive(Clone, Debug, PartialEq)] |
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.
What is the reason behind aggregating those two 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.
My "final" target is to substitute the dynamic error crate::Error
in public methods.
With this goal in mind, I looked at the code of nested methods where the error occurs. One of them is crate::jetstream::kv::entry which uses the private crate::Message::try_from which uses the private crate::stream::parse_headers.
This later beast parses both names and values and can return as dyn crate::Error
both versions. That's why my first intention was to tell "these 2 errors are kinds of possible parsing-related problems that can be unioned".
But after you question I made a second look and recognized that in fact you're right, and my aggregation was a bit "premature" because the same error is raised not in parsing, but building context, where these 2 errors aren't necessarily related to each other.
That's why now I'm going to roll back here and instead of aggregating these 2 errors from the beginning, keep them separate, but provide the crate::stream::ParseError
instead for all variants of the error that a parse_headers
function should return. In that case aggregation should make more sense.
wdyt?
RequestErrorKind::SubscriptionFailed => { | ||
BatchError::with_source(BatchErrorKind::Subscribe, err) | ||
} | ||
_ => panic!("Cannot convert error"), |
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.
Here you can see that the irrelevant kinds of Error creates a possible panic scenario, or at least a path you need to handle in some way.
std::io::ErrorKind::Other, | ||
"subscription dropped", | ||
))), | ||
None => Err(AckErrorKind::SubscriptionDropped.into()), |
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.
Errors are aggregated into Other
kind on purpose: to not clutter the possible enum variants with ones that it makes not much senes to match against for the user.
|
||
pub type AckError = crate::error::Error<AckErrorKind>; | ||
|
||
#[derive(Clone, Copy, Debug, PartialEq)] |
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.
All those errors mean something really bad happened internally in NATS protocol.
There is no point for the user to consider those variants, and there is nothing they can do to fix it or prevent it.
@@ -928,13 +934,14 @@ impl Subscriber { | |||
/// # Ok(()) | |||
/// # } | |||
/// ``` | |||
pub async fn unsubscribe(&mut self) -> Result<(), UnsubscribeError> { | |||
pub async fn unsubscribe(&mut self) -> Result<(), RequestError> { |
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.
As pointed out before - most variants are not valid for unsubscribe.
@@ -965,27 +972,18 @@ impl Subscriber { | |||
/// # Ok(()) | |||
/// # } | |||
/// ``` | |||
pub async fn unsubscribe_after(&mut self, unsub_after: u64) -> Result<(), UnsubscribeError> { | |||
pub async fn unsubscribe_after(&mut self, unsub_after: u64) -> Result<(), RequestError> { |
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 ;)
@@ -511,7 +512,7 @@ impl Service { | |||
/// # Ok(()) | |||
/// # } | |||
/// ``` | |||
pub async fn endpoint<S: ToString>(&self, subject: S) -> Result<Endpoint, Error> { | |||
pub async fn endpoint<S: ToString>(&self, subject: S) -> Result<Endpoint, RequestError> { |
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.
Maybe service API should have it's own Error. To consider.
Yeah, that's why it is draft )) I'll think deeper about it. My first intention was simple -- to standardize errors for 2 reasons:
But I see the reason in what you noticed above, so I'll need to rethink my approach. Maybe it makes sense to step back and (instead of merging specific errors into variants of enum) provide a marker kind for them like PS. I will definitely split this PR into several smaller ones (another reason why this beast is draft -- it is more for the discussion of the whole picture, than for merging) |
I'm closing this as stale, maybe will return and review the task later |
This is a continuation of the previous PR #1010
In this one I converted all crate-specific errors to specialized versions of the generic
errors::Error<T>
. Among other improvements I also convertedPublishError
,SubscribeError
andUnsubscribeError
into different variants of the sameRequestError
(which iscrate::error::Error<RequestErrorKind>
) to make it easier further improvement to return concrete errors instead ofBox<dyn crate::Error>
in jetstream and service