use crate::{error::MechanicsError, http::EndpointHttpClient, job::MechanicsExecutionLimits};
use std::{
sync::Arc,
time::{Duration, Instant},
};
#[derive(Debug, Clone)]
pub struct MechanicsPoolConfig {
pub(crate) worker_count: usize,
pub(crate) queue_capacity: usize,
pub(crate) enqueue_timeout: Duration,
pub(crate) run_timeout: Duration,
pub(crate) execution_limits: MechanicsExecutionLimits,
pub(crate) default_http_timeout_ms: Option<u64>,
pub(crate) default_http_response_max_bytes: Option<usize>,
pub(crate) restart_window: Duration,
pub(crate) max_restarts_in_window: usize,
pub(crate) endpoint_http_client: Option<Arc<dyn EndpointHttpClient>>,
#[cfg(test)]
pub(crate) force_worker_runtime_init_failure: bool,
}
impl Default for MechanicsPoolConfig {
fn default() -> Self {
let workers = std::thread::available_parallelism()
.map(|v| v.get())
.unwrap_or(1);
Self {
worker_count: workers.max(1),
queue_capacity: workers.saturating_mul(64).max(64),
enqueue_timeout: Duration::from_millis(500),
run_timeout: Duration::from_secs(30),
execution_limits: MechanicsExecutionLimits::default(),
default_http_timeout_ms: Some(120_000),
default_http_response_max_bytes: Some(8 * 1024 * 1024),
restart_window: Duration::from_secs(10),
max_restarts_in_window: 16,
endpoint_http_client: None,
#[cfg(test)]
force_worker_runtime_init_failure: false,
}
}
}
impl MechanicsPoolConfig {
pub fn new() -> Self {
Self::default()
}
pub(crate) fn validate(&self) -> Result<(), MechanicsError> {
if self.worker_count == 0 {
return Err(MechanicsError::runtime_pool("worker_count must be > 0"));
}
if self.queue_capacity == 0 {
return Err(MechanicsError::runtime_pool("queue_capacity must be > 0"));
}
if self.max_restarts_in_window == 0 {
return Err(MechanicsError::runtime_pool(
"max_restarts_in_window must be > 0",
));
}
if self.run_timeout.is_zero() {
return Err(MechanicsError::runtime_pool("run_timeout must be > 0"));
}
if Instant::now().checked_add(self.run_timeout).is_none() {
return Err(MechanicsError::runtime_pool(
"run_timeout is too large for the current platform clock",
));
}
if self.default_http_timeout_ms == Some(0) {
return Err(MechanicsError::runtime_pool(
"default_http_timeout_ms must be >= 1 when provided",
));
}
if self.default_http_response_max_bytes == Some(0) {
return Err(MechanicsError::runtime_pool(
"default_http_response_max_bytes must be >= 1 when provided",
));
}
self.execution_limits.validate()?;
Ok(())
}
pub fn with_worker_count(mut self, worker_count: usize) -> Self {
self.worker_count = worker_count;
self
}
pub fn with_queue_capacity(mut self, queue_capacity: usize) -> Self {
self.queue_capacity = queue_capacity;
self
}
pub fn with_enqueue_timeout(mut self, enqueue_timeout: Duration) -> Self {
self.enqueue_timeout = enqueue_timeout;
self
}
pub fn with_run_timeout(mut self, run_timeout: Duration) -> Self {
self.run_timeout = run_timeout;
self
}
pub fn with_execution_limits(mut self, execution_limits: MechanicsExecutionLimits) -> Self {
self.execution_limits = execution_limits;
self
}
pub fn with_default_http_timeout_ms(mut self, timeout_ms: Option<u64>) -> Self {
self.default_http_timeout_ms = timeout_ms;
self
}
pub fn with_default_http_response_max_bytes(mut self, max_bytes: Option<usize>) -> Self {
self.default_http_response_max_bytes = max_bytes;
self
}
pub fn with_restart_window(mut self, restart_window: Duration) -> Self {
self.restart_window = restart_window;
self
}
pub fn with_max_restarts_in_window(mut self, max_restarts_in_window: usize) -> Self {
self.max_restarts_in_window = max_restarts_in_window;
self
}
pub fn with_endpoint_http_client(
mut self,
endpoint_http_client: Arc<dyn EndpointHttpClient>,
) -> Self {
self.endpoint_http_client = Some(endpoint_http_client);
self
}
pub fn worker_count(&self) -> usize {
self.worker_count
}
pub fn queue_capacity(&self) -> usize {
self.queue_capacity
}
pub fn enqueue_timeout(&self) -> Duration {
self.enqueue_timeout
}
pub fn run_timeout(&self) -> Duration {
self.run_timeout
}
pub fn execution_limits(&self) -> MechanicsExecutionLimits {
self.execution_limits
}
pub fn default_http_timeout_ms(&self) -> Option<u64> {
self.default_http_timeout_ms
}
pub fn default_http_response_max_bytes(&self) -> Option<usize> {
self.default_http_response_max_bytes
}
pub fn restart_window(&self) -> Duration {
self.restart_window
}
pub fn max_restarts_in_window(&self) -> usize {
self.max_restarts_in_window
}
pub fn endpoint_http_client(&self) -> Option<Arc<dyn EndpointHttpClient>> {
self.endpoint_http_client.clone()
}
}