14
14
// limitations under the License.
15
15
use log:: info;
16
16
use parsec:: utils:: { ServiceBuilder , ServiceConfig } ;
17
- use signal_hook:: { flag, SIGTERM } ;
17
+ use signal_hook:: { flag, SIGHUP , SIGTERM } ;
18
18
use std:: io:: Error ;
19
19
use std:: sync:: {
20
20
atomic:: { AtomicBool , Ordering } ,
@@ -26,39 +26,57 @@ const CONFIG_FILE_PATH: &str = "./config.toml";
26
26
const MAIN_LOOP_DEFAULT_SLEEP : u64 = 10 ;
27
27
28
28
fn main ( ) -> Result < ( ) , Error > {
29
- let config_file =
29
+ // Register a boolean set to true when the SIGTERM signal is received.
30
+ let kill_signal = Arc :: new ( AtomicBool :: new ( false ) ) ;
31
+ // Register a boolean set to true when the SIGHUP signal is received.
32
+ let reload_signal = Arc :: new ( AtomicBool :: new ( false ) ) ;
33
+ flag:: register ( SIGTERM , kill_signal. clone ( ) ) ?;
34
+ flag:: register ( SIGHUP , reload_signal. clone ( ) ) ?;
35
+
36
+ let mut config_file =
30
37
:: std:: fs:: read_to_string ( CONFIG_FILE_PATH ) . expect ( "Failed to read configuration file" ) ;
31
- let config: ServiceConfig =
38
+ let mut config: ServiceConfig =
32
39
toml:: from_str ( & config_file) . expect ( "Failed to parse service configuration" ) ;
33
40
34
41
log_setup ( & config) ;
35
42
36
- info ! ( "PARSEC started." ) ;
37
-
38
- let front_end_handler = ServiceBuilder :: build_service ( & config) ;
39
-
40
- let listener = ServiceBuilder :: start_listener ( & config. listener ) ;
43
+ info ! ( "Parsec started. Configuring the service..." ) ;
41
44
42
45
// Multiple threads can not just have a reference of the front end handler because they could
43
46
// outlive the run function. It is needed to give them all ownership of the front end handler
44
47
// through an Arc.
45
- let front_end_handler = Arc :: from ( front_end_handler) ;
48
+ let mut front_end_handler = Arc :: from ( ServiceBuilder :: build_service ( & config) ) ;
49
+ let mut listener = ServiceBuilder :: start_listener ( & config. listener ) ;
50
+ let mut threadpool = ServiceBuilder :: build_threadpool ( config. core_settings . thread_pool_size ) ;
46
51
47
- // Register a boolean set to true when the SIGTERM signal is received.
48
- let kill_signal = Arc :: new ( AtomicBool :: new ( false ) ) ;
49
- flag:: register ( SIGTERM , kill_signal. clone ( ) ) ?;
52
+ // Notify systemd that the daemon is ready, the start command will block until this point.
53
+ let _ = sd_notify:: notify ( false , & [ sd_notify:: NotifyState :: Ready ] ) ;
50
54
51
- let threadpool = ServiceBuilder :: build_threadpool ( config . core_settings . thread_pool_size ) ;
55
+ info ! ( "Parsec is ready." ) ;
52
56
53
- info ! ( "PARSEC is ready." ) ;
57
+ while !kill_signal. load ( Ordering :: Relaxed ) {
58
+ if reload_signal. swap ( false , Ordering :: Relaxed ) {
59
+ let _ = sd_notify:: notify ( false , & [ sd_notify:: NotifyState :: Reloading ] ) ;
60
+ info ! ( "SIGHUP signal received. Reloading the configuration..." ) ;
54
61
55
- // Notify systemd that the daemon is ready, the start command will block until this point.
56
- let _ = sd_notify:: notify ( true , & [ sd_notify:: NotifyState :: Ready ] ) ;
62
+ threadpool. join ( ) ;
63
+
64
+ // Explicitely call drop now because otherwise Rust will drop these variables only
65
+ // after they have been overwritten, in which case some values/libraries might be
66
+ // initialized twice.
67
+ drop ( front_end_handler) ;
68
+ drop ( listener) ;
69
+ drop ( threadpool) ;
70
+
71
+ config_file = :: std:: fs:: read_to_string ( CONFIG_FILE_PATH )
72
+ . expect ( "Failed to read configuration file" ) ;
73
+ config = toml:: from_str ( & config_file) . expect ( "Failed to parse service configuration" ) ;
74
+ front_end_handler = Arc :: from ( ServiceBuilder :: build_service ( & config) ) ;
75
+ listener = ServiceBuilder :: start_listener ( & config. listener ) ;
76
+ threadpool = ServiceBuilder :: build_threadpool ( config. core_settings . thread_pool_size ) ;
57
77
58
- loop {
59
- if kill_signal. load ( Ordering :: Relaxed ) {
60
- info ! ( "SIGTERM signal received." ) ;
61
- break ;
78
+ let _ = sd_notify:: notify ( false , & [ sd_notify:: NotifyState :: Ready ] ) ;
79
+ info ! ( "Parsec configuration reloaded." ) ;
62
80
}
63
81
64
82
if let Some ( stream) = listener. accept ( ) {
@@ -76,8 +94,10 @@ fn main() -> Result<(), Error> {
76
94
}
77
95
}
78
96
79
- info ! ( "Shutting down PARSEC, waiting for all threads to finish." ) ;
97
+ let _ = sd_notify:: notify ( true , & [ sd_notify:: NotifyState :: Stopping ] ) ;
98
+ info ! ( "SIGTERM signal received. Shutting down Parsec, waiting for all threads to finish..." ) ;
80
99
threadpool. join ( ) ;
100
+ info ! ( "Parsec is now terminated." ) ;
81
101
82
102
Ok ( ( ) )
83
103
}
0 commit comments