1
0
mirror of https://github.com/fafhrd91/actix-net synced 2024-12-19 15:32:38 +01:00
actix-net/actix-rt/src/system.rs

249 lines
7.5 KiB
Rust
Raw Normal View History

2021-01-26 10:46:14 +01:00
use std::{
cell::RefCell,
future::Future,
io,
sync::atomic::{AtomicUsize, Ordering},
};
2018-12-10 04:55:40 +01:00
2021-01-26 10:46:14 +01:00
use tokio::{sync::mpsc::UnboundedSender, task::LocalSet};
2018-12-10 04:55:40 +01:00
2021-01-26 10:46:14 +01:00
use crate::{
arbiter::{Arbiter, SystemCommand},
builder::{Builder, SystemRunner},
};
2018-12-10 04:55:40 +01:00
static SYSTEM_COUNT: AtomicUsize = AtomicUsize::new(0);
2018-12-10 04:55:40 +01:00
/// System is a runtime manager.
#[derive(Clone, Debug)]
pub struct System {
id: usize,
2018-12-10 04:55:40 +01:00
sys: UnboundedSender<SystemCommand>,
arbiter: Arbiter,
stop_on_panic: bool,
}
thread_local!(
static CURRENT: RefCell<Option<System>> = RefCell::new(None);
);
impl System {
/// Constructs new system and sets it as current
pub(crate) fn construct(
sys: UnboundedSender<SystemCommand>,
arbiter: Arbiter,
stop_on_panic: bool,
) -> Self {
let sys = System {
sys,
arbiter,
stop_on_panic,
id: SYSTEM_COUNT.fetch_add(1, Ordering::SeqCst),
2018-12-10 04:55:40 +01:00
};
System::set_current(sys.clone());
sys
}
/// Build a new system with a customized tokio runtime.
///
2021-01-26 10:46:14 +01:00
/// This allows to customize the runtime. See [`Builder`] for more information.
2018-12-10 04:55:40 +01:00
pub fn builder() -> Builder {
Builder::new()
}
/// Create new system.
///
/// This method panics if it can not create tokio runtime
2021-01-26 10:46:14 +01:00
#[allow(clippy::new_ret_no_self)]
2018-12-10 04:55:40 +01:00
pub fn new<T: Into<String>>(name: T) -> SystemRunner {
Self::builder().name(name).build()
}
/// Create new system using provided tokio `LocalSet`.
///
2019-05-24 17:29:52 +02:00
/// This method panics if it can not spawn system arbiter
///
/// Note: This method uses provided `LocalSet` to create a `System` future only.
/// All the [`Arbiter`]s will be started in separate threads using their own tokio `Runtime`s.
/// It means that using this method currently it is impossible to make `actix-rt` work in the
2021-01-26 10:46:14 +01:00
/// alternative Tokio runtimes such as those provided by `tokio_compat`.
///
/// # Examples
2021-01-26 10:46:14 +01:00
/// ```
/// use tokio::{runtime::Runtime, task::LocalSet};
/// use actix_rt::System;
/// use futures_util::future::try_join_all;
///
/// async fn run_application() {
/// let first_task = tokio::spawn(async {
/// // ...
2021-01-26 10:46:14 +01:00
/// # println!("One task");
/// # Ok::<(),()>(())
/// });
///
/// let second_task = tokio::spawn(async {
/// // ...
2021-01-26 10:46:14 +01:00
/// # println!("Another task");
/// # Ok::<(),()>(())
/// });
///
/// try_join_all(vec![first_task, second_task])
/// .await
/// .expect("Some of the futures finished unexpectedly");
/// }
///
/// let runtime = tokio::runtime::Builder::new_multi_thread()
/// .worker_threads(2)
/// .enable_all()
/// .build()
/// .unwrap();
///
/// let actix_system_task = LocalSet::new();
/// let sys = System::run_in_tokio("actix-main-system", &actix_system_task);
/// actix_system_task.spawn_local(sys);
///
/// let rest_operations = run_application();
/// runtime.block_on(actix_system_task.run_until(rest_operations));
/// ```
2019-12-05 11:40:24 +01:00
pub fn run_in_tokio<T: Into<String>>(
name: T,
2019-12-05 11:40:24 +01:00
local: &LocalSet,
) -> impl Future<Output = io::Result<()>> {
2021-01-26 10:46:14 +01:00
Self::builder().name(name).build_async(local).run()
}
2021-01-26 10:46:14 +01:00
/// Consume the provided Tokio Runtime and start the `System` in it.
/// This method will create a `LocalSet` object and occupy the current thread
/// for the created `System` exclusively. All the other asynchronous tasks that
/// should be executed as well must be aggregated into one future, provided as the last
/// argument to this method.
///
/// Note: This method uses provided `Runtime` to create a `System` future only.
2021-01-26 10:46:14 +01:00
/// All the [`Arbiter`]s will be started in separate threads using their own Tokio `Runtime`s.
/// It means that using this method currently it is impossible to make `actix-rt` work in the
2021-01-26 10:46:14 +01:00
/// alternative Tokio runtimes such as those provided by `tokio_compat`.
///
/// # Arguments
///
/// - `name`: Name of the System
2021-01-26 10:46:14 +01:00
/// - `runtime`: A Tokio Runtime to run the system in.
/// - `rest_operations`: A future to be executed in the runtime along with the System.
///
/// # Examples
2021-01-26 10:46:14 +01:00
/// ```
/// use tokio::runtime::Runtime;
/// use actix_rt::System;
/// use futures_util::future::try_join_all;
///
/// async fn run_application() {
/// let first_task = tokio::spawn(async {
/// // ...
/// # println!("One task");
/// # Ok::<(),()>(())
/// });
///
/// let second_task = tokio::spawn(async {
/// // ...
/// # println!("Another task");
/// # Ok::<(),()>(())
/// });
///
/// try_join_all(vec![first_task, second_task])
/// .await
/// .expect("Some of the futures finished unexpectedly");
/// }
///
///
/// let runtime = tokio::runtime::Builder::new_multi_thread()
/// .worker_threads(2)
/// .enable_all()
/// .build()
/// .unwrap();
///
/// let rest_operations = run_application();
/// System::attach_to_tokio("actix-main-system", runtime, rest_operations);
/// ```
2021-01-26 10:46:14 +01:00
pub fn attach_to_tokio<Fut: Future>(
name: impl Into<String>,
runtime: tokio::runtime::Runtime,
rest_operations: Fut,
2021-01-26 10:46:14 +01:00
) -> Fut::Output {
let actix_system_task = LocalSet::new();
let sys = System::run_in_tokio(name.into(), &actix_system_task);
actix_system_task.spawn_local(sys);
runtime.block_on(actix_system_task.run_until(rest_operations))
}
2018-12-10 04:55:40 +01:00
/// Get current running system.
pub fn current() -> System {
CURRENT.with(|cell| match *cell.borrow() {
Some(ref sys) => sys.clone(),
None => panic!("System is not running"),
})
}
2021-01-26 10:46:14 +01:00
/// Check if current system has started.
pub fn is_set() -> bool {
2018-12-10 04:55:40 +01:00
CURRENT.with(|cell| cell.borrow().is_some())
}
/// Set current running system.
#[doc(hidden)]
pub fn set_current(sys: System) {
CURRENT.with(|s| {
*s.borrow_mut() = Some(sys);
})
}
/// Execute function with system reference.
pub fn with_current<F, R>(f: F) -> R
where
F: FnOnce(&System) -> R,
{
CURRENT.with(|cell| match *cell.borrow() {
Some(ref sys) => f(sys),
None => panic!("System is not running"),
})
}
2021-01-26 10:46:14 +01:00
/// Numeric system ID.
pub fn id(&self) -> usize {
self.id
}
2021-01-26 10:46:14 +01:00
/// Stop the system (with code 0).
2018-12-10 04:55:40 +01:00
pub fn stop(&self) {
self.stop_with_code(0)
}
/// Stop the system with a particular exit code.
pub fn stop_with_code(&self, code: i32) {
let _ = self.sys.send(SystemCommand::Exit(code));
2018-12-10 04:55:40 +01:00
}
pub(crate) fn sys(&self) -> &UnboundedSender<SystemCommand> {
&self.sys
}
/// Return status of 'stop_on_panic' option which controls whether the System is stopped when an
/// uncaught panic is thrown from a worker thread.
2021-01-26 10:46:14 +01:00
pub(crate) fn stop_on_panic(&self) -> bool {
2018-12-10 04:55:40 +01:00
self.stop_on_panic
}
2021-01-26 10:46:14 +01:00
/// Get shared reference to system arbiter.
2018-12-10 04:55:40 +01:00
pub fn arbiter(&self) -> &Arbiter {
&self.arbiter
}
2021-01-26 10:46:14 +01:00
/// This function will start tokio runtime and will finish once the `System::stop()` message
/// is called. Function `f` is called within tokio runtime context.
pub fn run<F>(f: F) -> io::Result<()>
2018-12-10 04:55:40 +01:00
where
F: FnOnce(),
2018-12-10 04:55:40 +01:00
{
Self::builder().run(f)
}
}