futu_opend/startup/phase4/
shutdown.rs1use std::time::Duration;
2
3pub(super) const SHUTDOWN_GRACE_PERIOD: Duration = Duration::from_secs(5);
4
5pub(super) type SurfaceJoinHandle = tokio::task::JoinHandle<anyhow::Result<()>>;
6pub(super) type BackgroundJoinHandle = tokio::task::JoinHandle<()>;
7
8pub(super) fn request_surface_shutdown(
9 shutdown_tx: &tokio::sync::watch::Sender<bool>,
10 reason: &'static str,
11) {
12 if let Err(error) = shutdown_tx.send(true) {
13 tracing::debug!(
14 reason,
15 error = %error,
16 "surface shutdown signal skipped; receivers already dropped"
17 );
18 }
19}
20
21async fn surface_task_result(handle: &mut SurfaceJoinHandle) -> anyhow::Result<()> {
22 match handle.await {
23 Ok(result) => result,
24 Err(error) => Err(anyhow::anyhow!("surface task join failed: {error}")),
25 }
26}
27
28pub(super) async fn surface_task_result_or_pending(
29 handle: &mut Option<SurfaceJoinHandle>,
30) -> anyhow::Result<()> {
31 match handle.as_mut() {
32 Some(handle) => surface_task_result(handle).await,
33 None => std::future::pending().await,
34 }
35}
36
37pub(super) fn log_surface_task_result(
38 surface: &'static str,
39 result: anyhow::Result<()>,
40) -> anyhow::Result<()> {
41 match result {
42 Ok(()) => {
43 tracing::warn!(surface, "surface task exited before daemon shutdown");
44 Ok(())
45 }
46 Err(error) => {
47 tracing::error!(surface, error = %error, "surface task failed");
48 Err(anyhow::anyhow!("{surface} surface task failed: {error}"))
49 }
50 }
51}
52
53pub(super) async fn await_surface_shutdown(
54 surface: &'static str,
55 mut handle: SurfaceJoinHandle,
56 grace_period: Duration,
57) {
58 match tokio::time::timeout(grace_period, &mut handle).await {
59 Ok(Ok(Ok(()))) => tracing::info!(surface, "surface task stopped gracefully"),
60 Ok(Ok(Err(error))) => {
61 tracing::error!(surface, error = %error, "surface task failed during shutdown")
62 }
63 Ok(Err(error)) => {
64 tracing::warn!(surface, error = %error, "surface task join failed during shutdown")
65 }
66 Err(_) => {
67 tracing::warn!(
68 surface,
69 grace_secs = grace_period.as_secs(),
70 "surface task did not stop in grace period; aborting fallback"
71 );
72 handle.abort();
73 }
74 }
75}
76
77pub(super) async fn await_background_shutdown(
78 task: &'static str,
79 mut handle: BackgroundJoinHandle,
80 grace_period: Duration,
81) {
82 match tokio::time::timeout(grace_period, &mut handle).await {
83 Ok(Ok(())) => tracing::info!(task, "background task stopped gracefully"),
84 Ok(Err(error)) => {
85 tracing::warn!(task, error = %error, "background task join failed during shutdown")
86 }
87 Err(_) => {
88 tracing::warn!(
89 task,
90 grace_secs = grace_period.as_secs(),
91 "background task did not stop in grace period; aborting fallback"
92 );
93 handle.abort();
94 }
95 }
96}