use std::cell::Cell;
use std::future::poll_fn;
use std::pin::Pin;
use std::process::Command;
use std::rc::Rc;
use std::task::Waker;
use std::time::Duration;
use std::{env, task, thread};
use arty_executor::{CycleOutcome, Executor};
use tracing::info;
const EXPECTED_FAILURE_CHILD_ENV: &str = "ARTY_EXECUTOR_EXPECTED_FAILURE_CHILD";
fn main() {
if env::var_os("IS_TESTING").is_some() && env::var_os(EXPECTED_FAILURE_CHILD_ENV).is_none() {
assert_failure_in_child();
} else {
run_example();
}
}
fn assert_failure_in_child() {
let executable = env::current_exe().expect("the running example necessarily has a current executable path");
let status = Command::new(executable)
.env(EXPECTED_FAILURE_CHILD_ENV, "1")
.status()
.expect("the example executable that is already running must be startable as a child");
assert!(!status.success(), "the child example must terminate after shutdown times out");
}
fn run_example() {
tracing_subscriber::fmt::init();
let mut executor_builder = Executor::builder();
if env::var_os("IS_TESTING").is_some() {
executor_builder = executor_builder.shutdown_timeout(Duration::ZERO);
}
let executor = unsafe { executor_builder.build() };
let tasks = executor.tasks();
let shutdown_signal = Rc::new(Cell::new(false));
let leaked_waker = Rc::new(Cell::new(None));
let mut leaked_join_handle = tasks.add({
let shutdown_signal = Rc::clone(&shutdown_signal);
let leaked_waker = Rc::clone(&leaked_waker);
async move {
poll_fn(|cx| {
leaked_waker.set(Some(cx.waker().clone()));
task::Poll::Ready(())
})
.await;
shutdown_signal.set(true);
}
});
simulate_join_handle_await(&mut leaked_join_handle);
let mut shutdown_started = false;
while executor.execute_cycle() != CycleOutcome::Shutdown {
if !shutdown_started && shutdown_signal.get() {
info!("Shutdown process is starting now. Please wait up to 60 seconds.");
shutdown_started = true;
executor.begin_shutdown();
continue;
}
thread::yield_now();
}
drop(leaked_join_handle);
drop(leaked_waker);
info!("Shutdown process completed successfully. This should never happen in this example.");
}
fn simulate_join_handle_await<R>(join_handle: &mut arty_executor::JoinHandle<R>) {
let mut cx = task::Context::from_waker(Waker::noop());
_ = Pin::new(join_handle).poll(&mut cx);
}