///|
pub(all) struct ReliabilityConfig {
seed : UInt64
operations : Int
fail_percent : Int
retry_limit : Int
backoff : Int
}
///|
pub(all) struct ReliabilityResult {
operations : Int
successes : Int
failures : Int
retries : Int
exhausted : Int
final_tick : Int
digest : UInt64
trace : Array[TraceEntry]
}
///|
pub fn reliability_config(
seed? : UInt64 = 9090UL,
operations? : Int = 10,
fail_percent? : Int = 30,
retry_limit? : Int = 2,
backoff? : Int = 2,
) -> ReliabilityConfig {
{
seed,
operations: if operations < 0 {
0
} else {
operations
},
fail_percent: clamp_percent(fail_percent),
retry_limit: if retry_limit < 0 {
0
} else {
retry_limit
},
backoff: if backoff < 0 {
0
} else {
backoff
},
}
}
///|
pub fn run_reliability_model(config : ReliabilityConfig) -> ReliabilityResult {
let sim = Sim::new(seed=config.seed)
for operation in 0.. Unit {
let mut attempt = 0
let mut tick = operation
let mut done = false
while attempt <= config.retry_limit && !done {
let name = "op:" + operation.to_string() + ":attempt:" + attempt.to_string()
ignore(sim.schedule_at(tick, name))
let failed = sim.next_int(100) < config.fail_percent
if failed {
sim.inc_counter("reliability_failure")
if attempt < config.retry_limit {
sim.inc_counter("reliability_retry")
tick += config.backoff * (attempt + 1)
} else {
sim.inc_counter("reliability_exhausted")
done = true
}
} else {
sim.inc_counter("reliability_success")
done = true
}
attempt += 1
}
}
///|
pub fn ReliabilityResult::success_rate_percent(self : ReliabilityResult) -> Int {
if self.operations == 0 {
0
} else {
self.successes * 100 / self.operations
}
}
///|
pub fn ReliabilityResult::summary(self : ReliabilityResult) -> ModelSummary {
{
name: "reliability",
digest: self.digest,
final_tick: self.final_tick,
events: self.successes + self.failures + self.retries,
}
}
///|
pub fn ReliabilityResult::line(self : ReliabilityResult) -> String {
"operations=" +
self.operations.to_string() +
" success_rate=" +
self.success_rate_percent().to_string() +
"%" +
" retries=" +
self.retries.to_string() +
" exhausted=" +
self.exhausted.to_string() +
" digest=" +
self.digest.to_string()
}