Repository navigation
Expand file tree
/
Copy pathweb-client.rs
More file actions
78 lines (69 loc) · 2.12 KB
/
Copy pathweb-client.rs
File metadata and controls
78 lines (69 loc) · 2.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//! Typical web client error handling.
#![allow(
dead_code,
clippy::missing_docs_in_private_items,
clippy::print_stderr,
reason = "Example"
)]
use ::neuer_error::{NeuErr, Result, provided_attachments, traits::*};
use ::std::time::Duration;
/// Mark errors whether they can be retried and/or were already retried.
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Default)]
enum ErrorStatus {
/// Not retryable.
#[default]
Permanent,
/// Retryable.
Temporary,
/// Was already retried, but still failed again.
Persistent,
}
// Automatically create a helper to easily retrieve the attachment.
provided_attachments!(
status(single: ErrorStatus) -> ErrorStatus { |status| status.copied().unwrap_or_default() }
);
/// Web client does some request. Returns some client-library error.
fn do_request(_request: String) -> Result<(), std::io::Error> {
Err(std::io::Error::new(std::io::ErrorKind::NotFound, "Interface eth1 not found"))
}
/// Your client method fetching some data from the server.
fn fetch_data(user: &str) -> Result<()> {
let request = format!("https://test.test/users/{user}?authenticated=yes-trust-me");
// Alternative 1.
do_request(request.clone())
.attach_override_with(|err| match err.kind() {
std::io::ErrorKind::NetworkDown => ErrorStatus::Temporary,
_ => ErrorStatus::Permanent,
})
.context_with(|| format!("Failed fetching data for user {user}"))?;
// Alternative 2.
do_request(request).map_err(|err| {
let status = match err.kind() {
std::io::ErrorKind::NetworkDown => ErrorStatus::Temporary,
_ => ErrorStatus::Permanent,
};
NeuErr::new_with_source(format!("Failed fetching data for user {user}"), err)
.attach_override(status)
})?;
Ok(())
}
fn main() {
// Retry requests based on error status.
loop {
match fetch_data("alice") {
Ok(data) => {
eprintln!("Request successful, data: {data:?}");
break;
}
Err(err) => {
if err.status() == ErrorStatus::Temporary {
eprintln!("Error: {err:#}; Retrying request in a bit..");
std::thread::sleep(Duration::from_secs(2));
} else {
eprintln!("Permanent error fetching data: {err}");
break;
}
}
}
}
}