1
1
use std:: time:: { Duration , Instant } ;
2
2
3
- use futures:: sink:: SinkExt ;
4
3
use futures:: channel:: mpsc:: Sender ;
4
+ use futures:: sink:: SinkExt ;
5
5
use futures_timer:: { Delay , TryFutureExt } ;
6
-
7
6
use url:: Url ;
8
- use crate :: ReportStatus ;
7
+
8
+ use crate :: url_value:: { Status , UrlValue } ;
9
+ use crate :: url_value:: Status :: { Healthy , Unhealthy , Unreacheable } ;
9
10
10
11
const STILL_UNHEALTHY_TIMEOUT : Duration = Duration :: from_secs ( 15 * 60 ) ; // 15 minutes
11
12
const TIMEOUT : Duration = Duration :: from_secs ( 5 ) ;
@@ -14,48 +15,47 @@ const FAST_PING: Duration = Duration::from_millis(800);
14
15
15
16
type ArrayDeque10 < T > = arraydeque:: ArrayDeque < [ T ; 10 ] , arraydeque:: Wrapping > ;
16
17
17
- #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
18
- enum Status {
19
- Healthy ,
20
- Unhealthy ,
21
- Unreacheable ,
22
- }
23
-
24
- use Status :: { Healthy , Unhealthy , Unreacheable } ;
25
-
26
- impl Status {
27
- fn is_good ( & self ) -> bool {
28
- * self == Healthy
29
- }
30
- }
31
-
32
18
pub async fn health_checker (
33
19
url : Url ,
34
- mut report_sender : Sender < ( Url , ReportStatus ) > ,
20
+ mut report_sender : Sender < ( Url , Status ) > ,
35
21
event_sender : ws:: Sender ,
36
22
database : sled:: Db ,
37
23
)
38
24
{
39
25
let mut last_status = ArrayDeque10 :: new ( ) ;
40
26
let mut in_bad_state_since = None ;
41
27
42
- let message = format ! ( "{},{:?}" , url, ReportStatus :: Healthy ) ;
43
- let _ = event_sender. send ( message) ;
44
-
45
28
loop {
46
- let status = match surf:: get ( & url) . timeout ( TIMEOUT ) . await {
47
- Ok ( ref resp) if resp. status ( ) . is_success ( ) => Healthy ,
48
- Ok ( resp) => Unhealthy ,
49
- Err ( e) => Unreacheable ,
29
+ let ( status, reason) = match surf:: get ( & url) . timeout ( TIMEOUT ) . await {
30
+ Ok ( ref resp) if resp. status ( ) . is_success ( ) => {
31
+ ( Healthy , resp. status ( ) . to_string ( ) )
32
+ } ,
33
+ Ok ( resp) => ( Unhealthy , resp. status ( ) . to_string ( ) ) ,
34
+ Err ( e) => ( Unreacheable , e. to_string ( ) ) ,
50
35
} ;
51
36
52
37
last_status. push_front ( status) ;
53
38
54
- match database. get ( url. as_str ( ) ) {
55
- Ok ( Some ( _) ) => ( ) ,
39
+ // update this value but do not erase the user custom data updates
40
+ let result = database. update_and_fetch ( url. as_str ( ) , |old| {
41
+ let old = old?;
42
+ let mut value: UrlValue = serde_json:: from_slice ( old) . unwrap ( ) ;
43
+ value. status = status;
44
+ value. reason = reason. clone ( ) ;
45
+ Some ( serde_json:: to_vec ( & value) . unwrap ( ) )
46
+ } ) ;
47
+
48
+ // retrieve the new value and deserialize it
49
+ // assign the current url this way it can be send in notifications
50
+ let value = match result {
51
+ Ok ( Some ( value) ) => {
52
+ let mut value: UrlValue = serde_json:: from_slice ( & value) . unwrap ( ) ;
53
+ value. url = Some ( url. to_string ( ) ) ;
54
+ value
55
+ } ,
56
56
Ok ( None ) => break ,
57
- Err ( e) => eprintln ! ( "{}: {}" , url, e) ,
58
- }
57
+ Err ( e) => { eprintln ! ( "{}: {}" , url, e) ; return } ,
58
+ } ;
59
59
60
60
let cap = last_status. capacity ( ) as f32 ;
61
61
let bads = last_status. iter ( ) . filter ( |s| !s. is_good ( ) ) . count ( ) as f32 ;
@@ -64,20 +64,20 @@ pub async fn health_checker(
64
64
if ratio >= 0.5 && in_bad_state_since. is_none ( ) {
65
65
in_bad_state_since = Some ( Instant :: now ( ) ) ;
66
66
67
- let report = ( url. clone ( ) , ReportStatus :: Unhealthy ) ;
67
+ let report = ( url. clone ( ) , Status :: Unhealthy ) ;
68
68
let _ = report_sender. send ( report) . await ;
69
69
70
- let message = format ! ( "{},{:?}" , url , ReportStatus :: Unhealthy ) ;
70
+ let message = serde_json :: to_string ( & value ) . unwrap ( ) ;
71
71
let _ = event_sender. send ( message) ;
72
72
}
73
73
74
74
if ratio == 0.0 && in_bad_state_since. is_some ( ) {
75
75
in_bad_state_since = None ;
76
76
77
- let report = ( url. clone ( ) , ReportStatus :: Healthy ) ;
77
+ let report = ( url. clone ( ) , Status :: Healthy ) ;
78
78
let _ = report_sender. send ( report) . await ;
79
79
80
- let message = format ! ( "{},{:?}" , url , ReportStatus :: Healthy ) ;
80
+ let message = serde_json :: to_string ( & value ) . unwrap ( ) ;
81
81
let _ = event_sender. send ( message) ;
82
82
}
83
83
@@ -89,17 +89,14 @@ pub async fn health_checker(
89
89
90
90
if let Some ( since) = in_bad_state_since {
91
91
if since. elapsed ( ) > STILL_UNHEALTHY_TIMEOUT {
92
- let report = ( url. clone ( ) , ReportStatus :: Unhealthy ) ;
92
+ let report = ( url. clone ( ) , Status :: Unhealthy ) ;
93
93
let _ = report_sender. send ( report) . await ;
94
94
95
- let message = format ! ( "{},{:?}" , url , ReportStatus :: Unhealthy ) ;
95
+ let message = serde_json :: to_string ( & value ) . unwrap ( ) ;
96
96
let _ = event_sender. send ( message) ;
97
97
98
98
in_bad_state_since = Some ( Instant :: now ( ) ) ;
99
99
}
100
100
}
101
101
}
102
-
103
- let message = format ! ( "{},{}" , url, "Removed" ) ;
104
- let _ = event_sender. send ( message) ;
105
102
}
0 commit comments