1
1
pub mod apprise;
2
2
pub mod checks;
3
3
pub mod config;
4
+ pub mod error;
4
5
pub mod log;
5
6
pub mod rpc;
6
7
pub mod shared;
7
8
pub mod state;
8
9
9
- use std:: net:: SocketAddr ;
10
+ use std:: { net:: SocketAddr , sync :: Arc } ;
10
11
11
12
use anyhow:: Context ;
12
13
use apprise:: AppRise ;
13
14
use checks:: all_checks;
14
15
use clap:: Parser ;
15
16
use config:: AppConfig ;
17
+ use error:: AsRetryError ;
16
18
use prometheus_exporter:: prometheus:: Registry ;
17
19
use rpc:: Rpc ;
18
20
use shared:: checksums:: Checksums ;
19
21
use state:: State ;
22
+ use tokio:: sync:: RwLock ;
23
+ use tokio_retry2:: { strategy:: ExponentialBackoff , Retry } ;
24
+
25
+ fn notify ( err : & std:: io:: Error , duration : std:: time:: Duration ) {
26
+ tracing:: info!( "Error {err:?} occurred at {duration:?}" ) ;
27
+ }
20
28
21
29
#[ tokio:: main]
22
30
async fn main ( ) -> anyhow:: Result < ( ) > {
@@ -36,37 +44,74 @@ async fn main() -> anyhow::Result<()> {
36
44
checksums. add ( code_path, code) ;
37
45
}
38
46
39
- let mut state = State :: new ( checksums) ;
40
- let registry = state. prometheus_registry ( ) ;
47
+ let state = Arc :: new ( RwLock :: new ( State :: new (
48
+ checksums,
49
+ config. initial_block_height ,
50
+ ) ) ) ;
51
+ let unlocked_state = state. read ( ) . await ;
52
+ let registry = unlocked_state. prometheus_registry ( ) ;
53
+ drop ( unlocked_state) ;
41
54
42
55
start_prometheus_exporter ( registry, config. prometheus_port ) ?;
43
56
57
+ let retry_strategy = retry_strategy ( ) ;
58
+
44
59
loop {
45
- let pre_state = state. clone ( ) ;
46
-
47
- let native_token = rpc. query_native_token ( ) . await ?;
48
- let block_height = state. next_block_height ( ) ;
49
- let epoch = rpc. query_current_epoch ( block_height) . await ?. unwrap_or ( 0 ) ;
50
- let block = rpc
51
- . query_block ( block_height, & state. checksums , epoch)
52
- . await ?;
53
- let total_supply_native = rpc. query_total_supply ( & native_token) . await ?;
54
-
55
- state. update ( block, total_supply_native) ;
56
-
57
- for check_kind in all_checks ( ) {
58
- let check_res = match check_kind {
59
- checks:: Checks :: BlockHeightCheck ( check) => check. run ( & pre_state, & state) . await ,
60
- checks:: Checks :: EpochCheck ( check) => check. run ( & pre_state, & state) . await ,
61
- checks:: Checks :: TotalSupplyNative ( check) => check. run ( & pre_state, & state) . await ,
62
- } ;
63
- if let Err ( error) = check_res {
64
- tracing:: error!( "Error: {}" , error. to_string( ) ) ;
65
- apprise. send_to_slack ( error. to_string ( ) ) . await ?;
66
- }
67
- }
68
-
69
- tracing:: info!( "Done block {}" , block_height) ;
60
+ Retry :: spawn_notify (
61
+ retry_strategy. clone ( ) ,
62
+ || async {
63
+ let pre_state_lock = state. read ( ) . await ;
64
+ let block_height = pre_state_lock. next_block_height ( ) ;
65
+ let checksums = pre_state_lock. checksums . clone ( ) ;
66
+ let pre_state = pre_state_lock. clone ( ) ;
67
+ drop ( pre_state_lock) ;
68
+
69
+ let native_token = rpc. query_native_token ( ) . await . into_retry_error ( ) ?;
70
+ let epoch = rpc
71
+ . query_current_epoch ( block_height)
72
+ . await
73
+ . into_retry_error ( ) ?
74
+ . unwrap_or ( 0 ) ;
75
+ let block = rpc
76
+ . query_block ( block_height, & checksums, epoch)
77
+ . await
78
+ . into_retry_error ( ) ?;
79
+ let total_supply_native = rpc
80
+ . query_total_supply ( & native_token)
81
+ . await
82
+ . into_retry_error ( ) ?;
83
+
84
+ let mut post_state_lock = state. write ( ) . await ;
85
+ post_state_lock. update ( block, total_supply_native) ;
86
+ let post_state = post_state_lock. clone ( ) ;
87
+ drop ( post_state_lock) ;
88
+
89
+ for check_kind in all_checks ( ) {
90
+ let check_res = match check_kind {
91
+ checks:: Checks :: BlockHeightCheck ( check) => {
92
+ check. run ( & pre_state, & post_state) . await
93
+ }
94
+ checks:: Checks :: EpochCheck ( check) => {
95
+ check. run ( & pre_state, & post_state) . await
96
+ }
97
+ checks:: Checks :: TotalSupplyNative ( check) => {
98
+ check. run ( & pre_state, & post_state) . await
99
+ }
100
+ } ;
101
+ if let Err ( error) = check_res {
102
+ tracing:: error!( "Error: {}" , error. to_string( ) ) ;
103
+ apprise
104
+ . send_to_slack ( error. to_string ( ) )
105
+ . await
106
+ . into_retry_error ( ) ?;
107
+ }
108
+ }
109
+
110
+ Ok ( ( ) )
111
+ } ,
112
+ notify,
113
+ )
114
+ . await ?;
70
115
}
71
116
}
72
117
@@ -80,3 +125,9 @@ fn start_prometheus_exporter(registry: Registry, port: u64) -> anyhow::Result<()
80
125
81
126
Ok ( ( ) )
82
127
}
128
+
129
+ fn retry_strategy ( ) -> ExponentialBackoff {
130
+ ExponentialBackoff :: from_millis ( 1000 )
131
+ . factor ( 1 )
132
+ . max_delay_millis ( 10000 )
133
+ }
0 commit comments