]>
git.proxmox.com Git - proxmox-backup.git/blob - proxmox-rest-server/src/state.rs
955e3ce350e3c6e3303b752de9b1f53c2b883b4a
2 use lazy_static
::lazy_static
;
7 use tokio
::signal
::unix
::{signal, SignalKind}
;
9 use pbs_tools
::broadcast_future
::BroadcastData
;
11 use crate::request_shutdown
;
13 #[derive(PartialEq, Copy, Clone, Debug)]
21 shutdown_listeners
: BroadcastData
<()>,
22 last_worker_listeners
: BroadcastData
<()>,
24 internal_task_count
: usize,
29 static ref SERVER_STATE
: Mutex
<ServerState
> = Mutex
::new(ServerState
{
30 mode
: ServerMode
::Normal
,
31 shutdown_listeners
: BroadcastData
::new(),
32 last_worker_listeners
: BroadcastData
::new(),
34 internal_task_count
: 0,
35 reload_request
: false,
39 /// Listen to ``SIGINT`` for server shutdown
41 /// This calls [request_shutdown] when receiving the signal.
42 pub fn catch_shutdown_signal() -> Result
<(), Error
> {
44 let mut stream
= signal(SignalKind
::interrupt())?
;
46 let future
= async
move {
47 while stream
.recv().await
.is_some() {
48 log
::info
!("got shutdown request (SIGINT)");
49 SERVER_STATE
.lock().unwrap().reload_request
= false;
54 let abort_future
= last_worker_future().map_err(|_
| {}
);
55 let task
= futures
::future
::select(future
, abort_future
);
57 tokio
::spawn(task
.map(|_
| ()));
62 /// Listen to ``SIGHUP`` for server reload
64 /// This calls [request_shutdown] when receiving the signal, and tries
65 /// to restart the server.
66 pub fn catch_reload_signal() -> Result
<(), Error
> {
68 let mut stream
= signal(SignalKind
::hangup())?
;
70 let future
= async
move {
71 while stream
.recv().await
.is_some() {
72 log
::info
!("got reload request (SIGHUP)");
73 SERVER_STATE
.lock().unwrap().reload_request
= true;
74 crate::request_shutdown();
78 let abort_future
= last_worker_future().map_err(|_
| {}
);
79 let task
= futures
::future
::select(future
, abort_future
);
81 tokio
::spawn(task
.map(|_
| ()));
86 pub(crate) fn is_reload_request() -> bool
{
87 let data
= SERVER_STATE
.lock().unwrap();
89 data
.mode
== ServerMode
::Shutdown
&& data
.reload_request
93 pub(crate) fn server_shutdown() {
94 let mut data
= SERVER_STATE
.lock().unwrap();
96 log
::info
!("request_shutdown");
98 data
.mode
= ServerMode
::Shutdown
;
100 data
.shutdown_listeners
.notify_listeners(Ok(()));
102 drop(data
); // unlock
107 /// Future to signal server shutdown
108 pub fn shutdown_future() -> impl Future
<Output
= ()> {
109 let mut data
= SERVER_STATE
.lock().unwrap();
116 /// Future to signal when last worker task finished
117 pub fn last_worker_future() -> impl Future
<Output
= Result
<(), Error
>> {
118 let mut data
= SERVER_STATE
.lock().unwrap();
119 data
.last_worker_listeners
.listen()
122 pub(crate) fn set_worker_count(count
: usize) {
123 SERVER_STATE
.lock().unwrap().worker_count
= count
;
128 pub(crate) fn check_last_worker() {
129 let mut data
= SERVER_STATE
.lock().unwrap();
131 if !(data
.mode
== ServerMode
::Shutdown
&& data
.worker_count
== 0 && data
.internal_task_count
== 0) { return; }
133 data
.last_worker_listeners
.notify_listeners(Ok(()));
136 /// Spawns a tokio task that will be tracked for reload
137 /// and if it is finished, notify the [last_worker_future] if we
138 /// are in shutdown mode.
139 pub fn spawn_internal_task
<T
>(task
: T
)
141 T
: Future
+ Send
+ '
static,
142 T
::Output
: Send
+ '
static,
144 let mut data
= SERVER_STATE
.lock().unwrap();
145 data
.internal_task_count
+= 1;
147 tokio
::spawn(async
move {
148 let _
= tokio
::spawn(task
).await
; // ignore errors
151 let mut data
= SERVER_STATE
.lock().unwrap();
152 if data
.internal_task_count
> 0 {
153 data
.internal_task_count
-= 1;