Sign in

    circuit_breaker

    A circuit breaker implementation in Moonbit

    Download zip
    Author
    Version
    0.1.3
    License
    Apache-2.0
    Last updated
    8 months ago
    Downloads
    26

    Dependencies


    #moonbit: backend: js

    #ryota0624/circuit_breaker_mbt

    A circuit breaker implementation for MoonBit inspired by https://github.com/sony/gobreaker

    #supported backends

    • js
    • native

    #Overview

    Circuit Breaker is a design pattern used to detect failures and prevent cascading failures in distributed systems. This implementation provides three states:

    • Closed: Normal operation, requests pass through
    • Open: Too many failures detected, requests are rejected immediately
    • HalfOpen: Testing if the system has recovered, limited requests allowed

    #Basic Usage

    ///|
    test "basic circuit breaker usage" {
    // Create a circuit breaker with default settings
    let settings : @ryota0624/circuit_breaker.Settings[Int, String] = @ryota0624/circuit_breaker.Settings::default()

    let cb = @ryota0624/circuit_breaker.CircuitBreaker::new(settings)

    // Execute a function through the circuit breaker
    let result = cb.run_sync(fn() -> Result[Int, String] { Ok(42) })

    inspect(result, content="Success(42)")
    }

    #Custom Configuration

    ///|
    test "custom circuit breaker configuration" {
    let mut current_time = 0L

    let settings : @ryota0624/circuit_breaker.Settings[Int, String] = @ryota0624/circuit_breaker.Settings::default()
    .with_name("MyService")
    .with_timeout(5000L) // 5 seconds timeout in Open state
    .with_max_requests(3L) // Allow 3 requests in HalfOpen state
    .with_get_now(fn() { current_time }) // Custom time source for testing

    let cb = @ryota0624/circuit_breaker.CircuitBreaker::new(settings)

    // Simulate failures to trip the circuit
    for i = 0; i < 6; i = i + 1 {
    let _ = cb.run_sync(fn() -> Result[Int, String] {
    Err("service unavailable")
    })
    }

    // Circuit should be open now
    inspect(cb.state(), content="Open")

    // Requests are rejected in Open state
    let result = cb.run_sync(fn() -> Result[Int, String] { Ok(1) })
    inspect(result, content="Rejected(OpenCircuit)")

    // Advance time past timeout
    current_time = 5000L

    // Circuit transitions to HalfOpen and allows request
    let result2 = cb.run_sync(fn() -> Result[Int, String] { Ok(1) })
    inspect(result2, content="Success(1)")
    }

    #Error Handling

    ///|
    test "error handling with circuit breaker" {
    let settings : @ryota0624/circuit_breaker.Settings[String, String] = @ryota0624/circuit_breaker.Settings::default()

    let cb = @ryota0624/circuit_breaker.CircuitBreaker::new(settings)

    // Handle different result types
    let result = cb.run_sync(fn() -> Result[String, String] { Err("error") })

    inspect(result, content="Failure(\"error\")")
    }

    CircuitBreakerError

    pub suberror CircuitBreakerError {
    TooManyRequests
    OpenCircuit
    }

    CircuitBreaker

    pub struct CircuitBreaker[T, E] {
    settings : Settings[T, E]
    state : State
    generation : Int64
    counts : Counts
    expiry : Int64
    get_now : () -> Int64
    }

    CircuitBreaker::counts

    fn[T, E] CircuitBreaker::counts(self : CircuitBreaker[T, E]) -> Counts

    CircuitBreaker::new

    fn[T, E] CircuitBreaker::new(settings : Settings[T, E]) -> CircuitBreaker[T, E]

    CircuitBreaker::run_async

    async fn[T, E] CircuitBreaker::run_async(self : CircuitBreaker[T, E], f : async () -> Result[T, E] noraise) -> CircuitBreakerRunResult[T, E] noraise

    CircuitBreaker::run_sync

    fn[T, E] CircuitBreaker::run_sync(self : CircuitBreaker[T, E], f : () -> Result[T, E]) -> CircuitBreakerRunResult[T, E]

    CircuitBreaker::state

    fn[T, E] CircuitBreaker::state(self : CircuitBreaker[T, E]) -> State

    CircuitBreaker::try_async

    async fn[T, E : Error] CircuitBreaker::try_async(self : CircuitBreaker[T, E], f : async () -> T raise E) -> T

    CircuitBreaker::try_sync

    fn[T, E : Error] CircuitBreaker::try_sync(self : CircuitBreaker[T, E], f : () -> T raise E) -> T raise

    CircuitBreakerRunResult

    pub enum CircuitBreakerRunResult[T, E] {
    Success(T)
    Failure(E)
    Rejected(CircuitBreakerError)
    }

    CircuitBreakerRunResult::map

    fn[T, E, U] CircuitBreakerRunResult::map(self : CircuitBreakerRunResult[T, E], f : (T) -> U) -> CircuitBreakerRunResult[U, E]

    CircuitBreakerRunResult::map_errors

    fn[T, E, U] CircuitBreakerRunResult::map_errors(self : CircuitBreakerRunResult[T, E], map_failure : (E) -> U, map_rejected : (CircuitBreakerError) -> U) -> Result[T, U]

    CircuitBreakerRunResult::unwrap_or_error

    fn[T, E : Error] CircuitBreakerRunResult::unwrap_or_error(self : CircuitBreakerRunResult[T, E]) -> T raise

    ConsecutiveResult

    pub enum ConsecutiveResult {
    Successes(Int64)
    Failures(Int64)
    }

    Counts

    pub struct Counts {
    requests : Int64
    total_successes : Int64
    total_failures : Int64
    consecutive : ConsecutiveResult
    }

    Counts::clear

    fn Counts::clear(self : Counts) -> Unit

    Counts::consecutive_failures

    fn Counts::consecutive_failures(self : Counts) -> Int64

    Counts::consecutive_successes

    fn Counts::consecutive_successes(self : Counts) -> Int64

    Counts::new

    fn Counts::new() -> Counts

    Counts::on_failure

    fn Counts::on_failure(self : Counts) -> Unit

    Counts::on_request

    fn Counts::on_request(self : Counts) -> Unit

    Counts::on_success

    fn Counts::on_success(self : Counts) -> Unit

    Settings

    pub struct Settings[T, E] {
    name : String
    max_requests : Int64
    interval : Int64
    timeout : Int64
    ready_to_trip : (Counts) -> Bool
    on_state_change : (String, State, State) -> Unit
    is_successful : (Result[T, E]) -> Bool
    get_now : () -> Int64
    }

    Settings::default

    fn[T, E] Settings::default() -> Settings[T, E]

    Settings::with_get_now

    fn[T, E] Settings::with_get_now(self : Settings[T, E], get_now : () -> Int64) -> Settings[T, E]

    Settings::with_interval

    fn[T, E] Settings::with_interval(self : Settings[T, E], interval : Int64) -> Settings[T, E]

    Settings::with_max_requests

    fn[T, E] Settings::with_max_requests(self : Settings[T, E], max_requests : Int64) -> Settings[T, E]

    Settings::with_name

    fn[T, E] Settings::with_name(self : Settings[T, E], name : String) -> Settings[T, E]

    Settings::with_timeout

    fn[T, E] Settings::with_timeout(self : Settings[T, E], timeout : Int64) -> Settings[T, E]

    State

    pub(all) enum State {
    Closed
    Open
    HalfOpen
    }

    impl Eq for State
    impl Show for State

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io