ayun_runtime/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
pub mod config;
mod instance;

use ayun_core::{Error, Result};

pub struct Runtime {
    inner: tokio::runtime::Runtime,
    config: config::Runtime,
}

impl Runtime {
    fn new(inner: tokio::runtime::Runtime, config: config::Runtime) -> Self {
        Self { inner, config }
    }

    fn try_from_config(config: config::Runtime) -> Result<Self, Error> {
        let mut builder = match config.kind {
            config::Kind::CurrentThread => tokio::runtime::Builder::new_current_thread(),
            config::Kind::MultiThread => tokio::runtime::Builder::new_multi_thread(),
            config::Kind::MultiThreadAlt => tokio::runtime::Builder::new_multi_thread_alt(),
        };

        if let Some(num) = config.worker_threads {
            builder.worker_threads(num);
        }

        if let Some(stack_size) = config.thread_stack_size {
            builder.thread_stack_size(stack_size);
        }

        if let Some(time) = config.keep_alive {
            builder.thread_keep_alive(std::time::Duration::from_millis(time));
        }

        if let Some(queue_interval) = config.global_queue_interval {
            builder.global_queue_interval(queue_interval);
        }

        let behavior = match config.unhandled_panic {
            config::UnhandledPanic::Ignore => tokio::runtime::UnhandledPanic::Ignore,
            config::UnhandledPanic::ShutdownRuntime => tokio::runtime::UnhandledPanic::Ignore,
        };

        if config.metrics_poll_count_histogram_enable {
            builder.enable_metrics_poll_count_histogram();
        }

        if config.disable_lifo_slot {
            builder.disable_lifo_slot();
        }

        let runtime = builder
            .enable_all()
            .max_io_events_per_tick(config.nevents)
            .max_blocking_threads(config.max_blocking_threads)
            .thread_name(config.thread_name.to_string())
            .event_interval(config.event_interval)
            .unhandled_panic(behavior)
            .build()?;

        Ok(Self::new(runtime, config))
    }

    pub fn config(self) -> config::Runtime {
        self.config
    }
}

impl std::ops::Deref for Runtime {
    type Target = tokio::runtime::Runtime;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

pub fn daemon(closure: ayun_core::Closure<Result<()>>) -> Result<()> {
    closure()?;

    let runtime = ayun_core::app().resolve::<Runtime>()?;

    runtime.block_on(shutdown());

    Ok(())
}

pub async fn shutdown() {
    let ctrl_c = async {
        tokio::signal::ctrl_c()
            .await
            .expect("failed to install Ctrl+C handler");
    };

    #[cfg(unix)]
    let terminate = async {
        tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
            .expect("fail to install the terminate signal handler")
            .recv()
            .await;
    };

    #[cfg(not(unix))]
    let terminate = std::future::pending::<()>();

    tokio::select! {
        _ = ctrl_c => {},
        _ = terminate => {},
    }

    tracing::warn!("signal received, starting graceful shutdown");
}