#![cfg(feature = "concurrency")]
#![allow(clippy::unwrap_used, clippy::expect_used)]
use core::sync::atomic::{AtomicUsize, Ordering};
use core::time::Duration;
use proxima_runtime::concurrency::law::ControlLaw;
use proxima_runtime::concurrency::{
Concurrency, ConcurrencyController, LawStep, Objective, Sample,
};
struct QueueDepthLaw {
setpoint: f64,
}
impl ControlLaw for QueueDepthLaw {
fn step(&mut self, ctx: LawStep) -> usize {
let error = self.setpoint - ctx.signal; if error.abs() < 1.0 {
return ctx.current;
}
if error > 0.0 {
ctx.stepped(1)
} else {
ctx.stepped(-1)
}
}
}
struct AppQueue {
depth: AtomicUsize,
target_concurrency: usize,
}
impl AppQueue {
fn observe_concurrency(&self, concurrency: usize) {
let depth = concurrency.saturating_sub(self.target_concurrency);
self.depth.store(depth, Ordering::Relaxed);
}
fn depth(&self) -> f64 {
self.depth.load(Ordering::Relaxed) as f64
}
}
#[test]
fn foreign_law_and_signal_drive_the_controller() {
let queue = std::sync::Arc::new(AppQueue {
depth: AtomicUsize::new(0),
target_concurrency: 12,
});
let signal_queue = std::sync::Arc::clone(&queue);
let knob: Concurrency = Concurrency::builder()
.signal_fn(move |_sample: &Sample| signal_queue.depth())
.objective(Objective::Maximize)
.law(QueueDepthLaw { setpoint: 1.0 })
.window(Duration::from_millis(100))
.bounds(1, 64)
.start(40)
.build()
.expect("foreign strategy builds via public API");
let mut controller = ConcurrencyController::new(knob);
let mut current = controller.target();
for _ in 0..100 {
queue.observe_concurrency(current);
current = controller.observe(Sample::seed(current));
}
assert!(
(11..=14).contains(¤t),
"foreign law converged near the queue setpoint, got {current}"
);
}
#[test]
fn foreign_whole_controller_replaces_the_strategy() {
use proxima_runtime::concurrency::strategy::ConcurrencyStrategy;
struct EveryOtherStrategy {
flip: bool,
}
impl ConcurrencyStrategy for EveryOtherStrategy {
fn next(&mut self, sample: Sample) -> usize {
self.flip = !self.flip;
if self.flip {
sample.concurrency + 1
} else {
sample.concurrency
}
}
}
let mut strategy = EveryOtherStrategy { flip: false };
assert_eq!(strategy.next(Sample::seed(8)), 9);
assert_eq!(strategy.next(Sample::seed(9)), 9);
}