use std::ops::Deref;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::task::JoinHandle;
use super::tickets::{now_millis, pending_count, policy_violated, TicketResult, TicketSystem};
pub struct Running {
system: Arc<TicketSystem>,
signal: Arc<AtomicBool>,
join: JoinHandle<()>,
}
impl Running {
pub(crate) fn new(
system: Arc<TicketSystem>,
signal: Arc<AtomicBool>,
join: JoinHandle<()>,
) -> Self {
Self {
system,
signal,
join,
}
}
pub fn signal(&self) -> Arc<AtomicBool> {
Arc::clone(&self.signal)
}
pub fn stop(&self) {
self.signal.store(true, Ordering::Relaxed);
}
pub async fn join(self) {
let _ = self.join.await;
}
pub fn abort(self) {
self.join.abort();
}
pub async fn run_dry(self) -> Vec<TicketResult> {
let started = Instant::now();
let policies = self.system.policies();
loop {
tokio::time::sleep(Duration::from_millis(20)).await;
if self.signal.load(Ordering::Relaxed) {
break;
}
if policy_violated(&policies, &self.system.stats) {
self.signal.store(true, Ordering::Relaxed);
break;
}
if let Some(limit) = policies.max_time {
if started.elapsed() >= limit {
self.signal.store(true, Ordering::Relaxed);
break;
}
}
if pending_count(&self.system) == 0 {
self.signal.store(true, Ordering::Relaxed);
break;
}
}
let _ = self.join.await;
self.system.stats.mark_finished(now_millis());
self.system.collect_results()
}
}
impl Deref for Running {
type Target = TicketSystem;
fn deref(&self) -> &TicketSystem {
&self.system
}
}