feat: harden community production foundation through story 1.5
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
use std::{env, num::ParseIntError};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
const DEFAULT_MAX_CONCURRENT_UNARY: usize = 64;
|
||||
const DEFAULT_MAX_CONCURRENT_SESSIONS: usize = 16;
|
||||
const MAX_CONCURRENCY: usize = 65_535;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct RuntimeLimits {
|
||||
@@ -21,52 +20,31 @@ impl Default for RuntimeLimits {
|
||||
}
|
||||
|
||||
impl RuntimeLimits {
|
||||
pub fn from_env() -> Result<Self, RuntimeLimitsConfigError> {
|
||||
pub fn try_new(
|
||||
max_concurrent_unary: usize,
|
||||
max_concurrent_sessions: usize,
|
||||
) -> Result<Self, RuntimeLimitsConfigError> {
|
||||
if !(1..=MAX_CONCURRENCY).contains(&max_concurrent_unary) {
|
||||
return Err(RuntimeLimitsConfigError::OutOfRange {
|
||||
field: "runtime.max_concurrent_unary",
|
||||
});
|
||||
}
|
||||
if !(1..=MAX_CONCURRENCY).contains(&max_concurrent_sessions) {
|
||||
return Err(RuntimeLimitsConfigError::OutOfRange {
|
||||
field: "runtime.max_concurrent_sessions",
|
||||
});
|
||||
}
|
||||
Ok(Self {
|
||||
max_concurrent_unary: parse_limit(
|
||||
"CRANK_RUNTIME_MAX_CONCURRENT_UNARY",
|
||||
DEFAULT_MAX_CONCURRENT_UNARY,
|
||||
)?,
|
||||
max_concurrent_sessions: parse_limit(
|
||||
"CRANK_RUNTIME_MAX_CONCURRENT_SESSIONS",
|
||||
DEFAULT_MAX_CONCURRENT_SESSIONS,
|
||||
)?,
|
||||
max_concurrent_unary,
|
||||
max_concurrent_sessions,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_limit(name: &'static str, default: usize) -> Result<usize, RuntimeLimitsConfigError> {
|
||||
match env::var(name) {
|
||||
Ok(raw) => {
|
||||
let value =
|
||||
raw.parse::<usize>()
|
||||
.map_err(|source| RuntimeLimitsConfigError::InvalidValue {
|
||||
name,
|
||||
value: raw,
|
||||
source,
|
||||
})?;
|
||||
if value == 0 {
|
||||
return Err(RuntimeLimitsConfigError::ZeroValue { name });
|
||||
}
|
||||
Ok(value)
|
||||
}
|
||||
Err(env::VarError::NotPresent) => Ok(default),
|
||||
Err(env::VarError::NotUnicode(_)) => Err(RuntimeLimitsConfigError::InvalidUnicode { name }),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[derive(Debug, Error, Eq, PartialEq)]
|
||||
pub enum RuntimeLimitsConfigError {
|
||||
#[error("{name} must contain valid UTF-8")]
|
||||
InvalidUnicode { name: &'static str },
|
||||
#[error("{name} must be a positive integer, got {value}")]
|
||||
InvalidValue {
|
||||
name: &'static str,
|
||||
value: String,
|
||||
source: ParseIntError,
|
||||
},
|
||||
#[error("{name} must be greater than zero")]
|
||||
ZeroValue { name: &'static str },
|
||||
#[error("runtime limit is outside its allowed bounds: {field}")]
|
||||
OutOfRange { field: &'static str },
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -76,28 +54,17 @@ mod tests {
|
||||
#[test]
|
||||
fn defaults_are_positive() {
|
||||
let limits = RuntimeLimits::default();
|
||||
|
||||
assert!(limits.max_concurrent_unary > 0);
|
||||
assert!(limits.max_concurrent_sessions > 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_zero_limit_values() {
|
||||
unsafe {
|
||||
std::env::set_var("CRANK_RUNTIME_MAX_CONCURRENT_UNARY", "0");
|
||||
}
|
||||
|
||||
let error = RuntimeLimits::from_env().unwrap_err();
|
||||
|
||||
assert!(matches!(
|
||||
error,
|
||||
RuntimeLimitsConfigError::ZeroValue {
|
||||
name: "CRANK_RUNTIME_MAX_CONCURRENT_UNARY"
|
||||
fn value_constructor_rejects_zero() {
|
||||
assert_eq!(
|
||||
RuntimeLimits::try_new(0, 1).unwrap_err(),
|
||||
RuntimeLimitsConfigError::OutOfRange {
|
||||
field: "runtime.max_concurrent_unary"
|
||||
}
|
||||
));
|
||||
|
||||
unsafe {
|
||||
std::env::remove_var("CRANK_RUNTIME_MAX_CONCURRENT_UNARY");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user