use orchestral_core::store::Event;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ConcurrencyDecision {
InterruptAndStartNew,
Reject {
reason: String,
},
Queue,
Parallel,
MergeIntoRunning,
}
impl ConcurrencyDecision {
pub fn reject(reason: impl Into<String>) -> Self {
Self::Reject {
reason: reason.into(),
}
}
}
#[derive(Debug, Clone)]
pub struct RunningState {
pub active_count: usize,
pub is_processing: bool,
pub is_waiting_user: bool,
pub is_waiting_event: bool,
}
impl RunningState {
pub fn new() -> Self {
Self {
active_count: 0,
is_processing: false,
is_waiting_user: false,
is_waiting_event: false,
}
}
pub fn has_active(&self) -> bool {
self.active_count > 0
}
pub fn is_idle(&self) -> bool {
self.active_count == 0
}
}
impl Default for RunningState {
fn default() -> Self {
Self::new()
}
}
pub trait ConcurrencyPolicy: Send + Sync {
fn decide(&self, running: &RunningState, new_event: &Event) -> ConcurrencyDecision;
}
pub struct DefaultConcurrencyPolicy;
impl ConcurrencyPolicy for DefaultConcurrencyPolicy {
fn decide(&self, running: &RunningState, _new_event: &Event) -> ConcurrencyDecision {
if running.is_idle() {
ConcurrencyDecision::InterruptAndStartNew
} else {
ConcurrencyDecision::InterruptAndStartNew
}
}
}
pub struct QueueConcurrencyPolicy;
impl ConcurrencyPolicy for QueueConcurrencyPolicy {
fn decide(&self, running: &RunningState, _new_event: &Event) -> ConcurrencyDecision {
if running.is_idle() {
ConcurrencyDecision::InterruptAndStartNew
} else {
ConcurrencyDecision::reject(
"Queue policy is not implemented; use interrupt/parallel/reject policy",
)
}
}
}
pub struct ParallelConcurrencyPolicy {
pub max_parallel: usize,
}
impl ParallelConcurrencyPolicy {
pub fn new(max_parallel: usize) -> Self {
Self { max_parallel }
}
}
impl Default for ParallelConcurrencyPolicy {
fn default() -> Self {
Self::new(4)
}
}
impl ConcurrencyPolicy for ParallelConcurrencyPolicy {
fn decide(&self, running: &RunningState, _new_event: &Event) -> ConcurrencyDecision {
if running.active_count >= self.max_parallel {
ConcurrencyDecision::reject(format!(
"Maximum parallel interactions ({}) reached",
self.max_parallel
))
} else {
ConcurrencyDecision::Parallel
}
}
}
pub struct MergeConcurrencyPolicy;
impl ConcurrencyPolicy for MergeConcurrencyPolicy {
fn decide(&self, running: &RunningState, _new_event: &Event) -> ConcurrencyDecision {
if running.is_idle() {
ConcurrencyDecision::InterruptAndStartNew
} else {
ConcurrencyDecision::MergeIntoRunning
}
}
}
pub struct RejectWhenBusyConcurrencyPolicy;
impl ConcurrencyPolicy for RejectWhenBusyConcurrencyPolicy {
fn decide(&self, running: &RunningState, _new_event: &Event) -> ConcurrencyDecision {
if running.is_idle() {
ConcurrencyDecision::InterruptAndStartNew
} else {
ConcurrencyDecision::reject("System is busy processing another request")
}
}
}