1
0
mirror of https://github.com/fafhrd91/actix-net synced 2024-11-27 20:12:58 +01:00

Merge pull request #22 from GeorgeHahn/with-external-runtime

Allow Actix to be started on an external CurrentThread runtime
This commit is contained in:
Nikolay Kim 2019-06-22 08:53:19 +06:00 committed by GitHub
commit 1c04ad3238
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 77 additions and 2 deletions

View File

@ -1,11 +1,12 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::io; use std::io;
use futures::future;
use futures::future::{lazy, Future}; use futures::future::{lazy, Future};
use futures::sync::mpsc::unbounded; use futures::sync::mpsc::unbounded;
use futures::sync::oneshot::{channel, Receiver}; use futures::sync::oneshot::{channel, Receiver};
use tokio_current_thread::CurrentThread; use tokio_current_thread::{CurrentThread, Handle};
use tokio_reactor::Reactor; use tokio_reactor::Reactor;
use tokio_timer::clock::Clock; use tokio_timer::clock::Clock;
use tokio_timer::timer::Timer; use tokio_timer::timer::Timer;
@ -69,6 +70,13 @@ impl Builder {
self.create_runtime(|| {}) self.create_runtime(|| {})
} }
/// Create new System that can run asynchronously.
///
/// This method panics if it cannot start the system arbiter
pub(crate) fn build_async(self, executor: Handle) -> AsyncSystemRunner {
self.create_async_runtime(executor)
}
/// This function will start tokio runtime and will finish once the /// This function will start tokio runtime and will finish once the
/// `System::stop()` message get called. /// `System::stop()` message get called.
/// Function `f` get called within tokio runtime context. /// Function `f` get called within tokio runtime context.
@ -79,6 +87,21 @@ impl Builder {
self.create_runtime(f).run() self.create_runtime(f).run()
} }
fn create_async_runtime(self, executor: Handle) -> AsyncSystemRunner {
let (stop_tx, stop) = channel();
let (sys_sender, sys_receiver) = unbounded();
let system = System::construct(sys_sender, Arbiter::new_system(), self.stop_on_panic);
// system arbiter
let arb = SystemArbiter::new(stop_tx, sys_receiver);
// start the system arbiter
executor.spawn(arb).expect("could not start system arbiter");
AsyncSystemRunner { stop, system }
}
fn create_runtime<F>(self, f: F) -> SystemRunner fn create_runtime<F>(self, f: F) -> SystemRunner
where where
F: FnOnce() + 'static, F: FnOnce() + 'static,
@ -127,6 +150,42 @@ impl Builder {
} }
} }
#[derive(Debug)]
pub(crate) struct AsyncSystemRunner {
stop: Receiver<i32>,
system: System,
}
impl AsyncSystemRunner {
/// This function will start event loop and returns a future that
/// resolves once the `System::stop()` function is called.
pub(crate) fn run_nonblocking(self) -> Box<Future<Item = (), Error = io::Error> + Send + 'static> {
let AsyncSystemRunner { stop, .. } = self;
// run loop
Box::new(future::lazy(|| {
Arbiter::run_system();
stop.then(|res| match res {
Ok(code) => {
if code != 0 {
Err(io::Error::new(
io::ErrorKind::Other,
format!("Non-zero exit code: {}", code),
))
} else {
Ok(())
}
}
Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)),
})
.then(|result| {
Arbiter::stop_system();
result
})
}))
}
}
/// Helper object that runs System's event loop /// Helper object that runs System's event loop
#[must_use = "SystemRunner must be run"] #[must_use = "SystemRunner must be run"]
#[derive(Debug)] #[derive(Debug)]

View File

@ -3,9 +3,11 @@ use std::io;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use futures::sync::mpsc::UnboundedSender; use futures::sync::mpsc::UnboundedSender;
use futures::Future;
use tokio_current_thread::Handle;
use crate::arbiter::{Arbiter, SystemCommand}; use crate::arbiter::{Arbiter, SystemCommand};
use crate::builder::{Builder, SystemRunner}; use crate::builder::{AsyncSystemRunner, Builder, SystemRunner};
static SYSTEM_COUNT: AtomicUsize = AtomicUsize::new(0); static SYSTEM_COUNT: AtomicUsize = AtomicUsize::new(0);
@ -55,6 +57,20 @@ impl System {
Self::builder().name(name).build() Self::builder().name(name).build()
} }
#[allow(clippy::new_ret_no_self)]
/// Create new system using provided CurrentThread Handle.
///
/// This method panics if it can not spawn system arbiter
pub fn run_in_executor<T: Into<String>>(
name: T,
executor: Handle,
) -> Box<Future<Item = (), Error = io::Error> + Send + 'static> {
Self::builder()
.name(name)
.build_async(executor)
.run_nonblocking()
}
/// Get current running system. /// Get current running system.
pub fn current() -> System { pub fn current() -> System {
CURRENT.with(|cell| match *cell.borrow() { CURRENT.with(|cell| match *cell.borrow() {