@@ -28,10 +28,13 @@ use std::sync::Arc;
28
28
29
29
use axum_server:: tls_rustls:: RustlsConfig ;
30
30
use axum_server:: Handle ;
31
+ use derive_more:: derive:: Display ;
31
32
use derive_more:: Constructor ;
32
33
use futures:: future:: BoxFuture ;
34
+ use thiserror:: Error ;
33
35
use tokio:: sync:: oneshot:: { Receiver , Sender } ;
34
36
use torrust_tracker_configuration:: AccessTokens ;
37
+ use tracing:: { instrument, Level } ;
35
38
36
39
use super :: routes:: router;
37
40
use crate :: bootstrap:: jobs:: Started ;
@@ -43,9 +46,10 @@ use crate::servers::registar::{ServiceHealthCheckJob, ServiceRegistration, Servi
43
46
use crate :: servers:: signals:: { graceful_shutdown, Halted } ;
44
47
45
48
/// Errors that can occur when starting or stopping the API server.
46
- #[ derive( Debug ) ]
49
+ #[ derive( Debug , Error ) ]
47
50
pub enum Error {
48
- Error ( String ) ,
51
+ #[ error( "Error when starting or stopping the API server" ) ]
52
+ FailedToStartOrStop ( String ) ,
49
53
}
50
54
51
55
/// An alias for the `ApiServer` struct with the `Stopped` state.
@@ -62,31 +66,39 @@ pub type RunningApiServer = ApiServer<Running>;
62
66
/// It's a state machine that can be in one of two
63
67
/// states: `Stopped` or `Running`.
64
68
#[ allow( clippy:: module_name_repetitions) ]
65
- pub struct ApiServer < S > {
69
+ #[ derive( Debug , Display ) ]
70
+ pub struct ApiServer < S >
71
+ where
72
+ S : std:: fmt:: Debug + std:: fmt:: Display ,
73
+ {
66
74
pub state : S ,
67
75
}
68
76
69
77
/// The `Stopped` state of the `ApiServer` struct.
78
+ #[ derive( Debug , Display ) ]
79
+ #[ display( "Stopped: {launcher}" ) ]
70
80
pub struct Stopped {
71
81
launcher : Launcher ,
72
82
}
73
83
74
84
/// The `Running` state of the `ApiServer` struct.
85
+ #[ derive( Debug , Display ) ]
86
+ #[ display( "Running (with local address): {local_addr}" ) ]
75
87
pub struct Running {
76
- pub binding : SocketAddr ,
88
+ pub local_addr : SocketAddr ,
77
89
pub halt_task : tokio:: sync:: oneshot:: Sender < Halted > ,
78
90
pub task : tokio:: task:: JoinHandle < Launcher > ,
79
91
}
80
92
81
93
impl Running {
82
94
#[ must_use]
83
95
pub fn new (
84
- binding : SocketAddr ,
96
+ local_addr : SocketAddr ,
85
97
halt_task : tokio:: sync:: oneshot:: Sender < Halted > ,
86
98
task : tokio:: task:: JoinHandle < Launcher > ,
87
99
) -> Self {
88
100
Self {
89
- binding ,
101
+ local_addr ,
90
102
halt_task,
91
103
task,
92
104
}
@@ -110,6 +122,7 @@ impl ApiServer<Stopped> {
110
122
/// # Panics
111
123
///
112
124
/// It would panic if the bound socket address cannot be sent back to this starter.
125
+ #[ instrument( skip( self , tracker, form, access_tokens) , err, ret( Display , level = Level :: INFO ) ) ]
113
126
pub async fn start (
114
127
self ,
115
128
tracker : Arc < Tracker > ,
@@ -157,13 +170,14 @@ impl ApiServer<Running> {
157
170
/// # Errors
158
171
///
159
172
/// It would return an error if the channel for the task killer signal was closed.
173
+ #[ instrument( skip( self ) , err, ret( Display , level = Level :: INFO ) ) ]
160
174
pub async fn stop ( self ) -> Result < ApiServer < Stopped > , Error > {
161
175
self . state
162
176
. halt_task
163
177
. send ( Halted :: Normal )
164
- . map_err ( |_| Error :: Error ( "Task killer channel was closed." . to_string ( ) ) ) ?;
178
+ . map_err ( |_| Error :: FailedToStartOrStop ( "Task killer channel was closed." . to_string ( ) ) ) ?;
165
179
166
- let launcher = self . state . task . await . map_err ( |e| Error :: Error ( e. to_string ( ) ) ) ?;
180
+ let launcher = self . state . task . await . map_err ( |e| Error :: FailedToStartOrStop ( e. to_string ( ) ) ) ?;
167
181
168
182
Ok ( ApiServer {
169
183
state : Stopped { launcher } ,
@@ -178,6 +192,7 @@ impl ApiServer<Running> {
178
192
/// This function will return an error if unable to connect.
179
193
/// Or if there request returns an error code.
180
194
#[ must_use]
195
+ #[ instrument( skip( ) ) ]
181
196
pub fn check_fn ( binding : & SocketAddr ) -> ServiceHealthCheckJob {
182
197
let url = format ! ( "http://{binding}/api/health_check" ) ; // DevSkim: ignore DS137138
183
198
@@ -199,6 +214,16 @@ pub struct Launcher {
199
214
tls : Option < RustlsConfig > ,
200
215
}
201
216
217
+ impl std:: fmt:: Display for Launcher {
218
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
219
+ if self . tls . is_some ( ) {
220
+ write ! ( f, "(with socket): {}, using TLS" , self . bind_to, )
221
+ } else {
222
+ write ! ( f, "(with socket): {}, without TLS" , self . bind_to, )
223
+ }
224
+ }
225
+ }
226
+
202
227
impl Launcher {
203
228
/// Starts the API server with graceful shutdown.
204
229
///
@@ -210,6 +235,7 @@ impl Launcher {
210
235
///
211
236
/// Will panic if unable to bind to the socket, or unable to get the address of the bound socket.
212
237
/// Will also panic if unable to send message regarding the bound socket address.
238
+ #[ instrument( skip( self , tracker, access_tokens, tx_start, rx_halt) ) ]
213
239
pub fn start (
214
240
& self ,
215
241
tracker : Arc < Tracker > ,
0 commit comments