nobreak 0.1.0

nobreak is a minimal circuit breaker for your functions
Documentation
# nobreak

A minimal circuit breaker library for Rust with both sync and async support.

## Usage

Async (enabled by default via the `tokio` feature):

```rust
let cb = nobreak::breaker();

let result = cb
    .call_async(|| async {
        do_something().await
    })
    .await
    .map_err(|e| e.into_inner().unwrap())?;
```

Sync:

```rust
let cb = nobreak::breaker();

let result = cb
    .call(|| {
        do_something()
    })
    .map_err(|e| e.into_inner().unwrap())?;
```

Both use sensible defaults: 5 failure threshold, 2 success threshold for half-open recovery, and a 30s open duration.

The circuit breaker tracks consecutive failures. Once the failure threshold is reached, the circuit opens and subsequent calls are rejected immediately with `CircuitError::Open` without executing the function. After the open duration elapses, the circuit transitions to half-open and allows calls through again. If enough consecutive successes occur, the circuit closes. If a call fails in half-open, the circuit reopens.

## Features

The `tokio` feature is enabled by default, providing `call_async`. To use only the sync API:

```toml
nobreak = { version = "0.1", default-features = false }
```

## Builder

For more control, use the builder:

```rust
use std::time::Duration;

let cb = nobreak::builder()
    .with_failure_threshold(10)
    .with_success_threshold(3)
    .with_open_duration(Duration::from_secs(60))
    .build();

cb.call_async(|| async {
    do_something().await
})
.await?;
```

## Configuration

- `with_failure_threshold(n)` — number of consecutive failures before the circuit opens (default: 5)
- `with_success_threshold(n)` — number of consecutive successes in half-open state before the circuit closes (default: 2)
- `with_open_duration(dur)` — how long the circuit stays open before transitioning to half-open (default: 30s)

## Circuit states

- **Closed** — normal operation, calls pass through. Consecutive failures are tracked; a success resets the count.
- **Open** — calls are rejected immediately with `CircuitError::Open`. After `open_duration` elapses, transitions to half-open.
- **Half-open** — calls pass through to test recovery. A failure reopens the circuit. Once `success_threshold` consecutive successes occur, the circuit closes.

Inspect the current state at any time:

```rust
let state = cb.state(); // CircuitState::Closed | Open | HalfOpen
```

## Error handling

`CircuitError<E>` has two variants:

- `Failed { error }` — the operation was executed but returned an error
- `Open` — the circuit is open; the operation was not executed

Call `.into_inner()` to extract the underlying error as an `Option<E>` (returns `None` for `Open`).