From feb249c94963a21c85fbfb00a08e7932d544c266 Mon Sep 17 00:00:00 2001 From: dawn Date: Thu, 8 Oct 2026 15:42:22 +0300 Subject: [PATCH] bobbin/{bobbin,knot-proxy}: make the mirror's circuit breaker threshold and cooldown configurable Signed-off-by: dawn --- bobbin/crates/bobbin/src/config.rs | 13 +++++++++++++ bobbin/crates/bobbin/src/main.rs | 16 ++++++++++++++-- bobbin/crates/knot-proxy/src/mirror.rs | 21 +++++++++++++++++++-- bobbin/example.toml | 15 +++++++++++++++ docs/src/content/docs/reference/bobbin.md | 2 ++ 5 files changed, 63 insertions(+), 4 deletions(-) diff --git a/bobbin/crates/bobbin/src/config.rs b/bobbin/crates/bobbin/src/config.rs index ad32af175..c3d05ac3e 100644 --- a/bobbin/crates/bobbin/src/config.rs +++ b/bobbin/crates/bobbin/src/config.rs @@ -39,6 +39,8 @@ const KNOWN_KEYS: &[&str] = &[ "codesearch.zoekt_url", "codesearch.zoekt_auth", "mirror.url", + "mirror.breaker_threshold", + "mirror.breaker_cooldown_secs", "pocket.url", "log.format", "log.filter", @@ -73,6 +75,8 @@ const KNOWN_ENVS: &[&str] = &[ "BOBBIN_CODESEARCH_ZOEKT_URL", "BOBBIN_CODESEARCH_ZOEKT_AUTH", "BOBBIN_MIRROR_URL", + "BOBBIN_MIRROR_BREAKER_THRESHOLD", + "BOBBIN_MIRROR_BREAKER_COOLDOWN_SECS", "BOBBIN_POCKET_URL", "BOBBIN_LOG_FORMAT", "BOBBIN_LOG", @@ -318,6 +322,15 @@ pub struct MirrorConfig { /// Origin of the mirror (gitmirror) XRPC server. #[config(env = "BOBBIN_MIRROR_URL")] pub url: Option, + + /// failures in a row before requests to the mirror stop for the cooldown + /// and answer `knot circuit breaker open` straight away. + #[config(env = "BOBBIN_MIRROR_BREAKER_THRESHOLD", default = 3)] + pub breaker_threshold: u32, + + /// seconds requests to the mirror stay stopped after the breaker opens. + #[config(env = "BOBBIN_MIRROR_BREAKER_COOLDOWN_SECS", default = 30)] + pub breaker_cooldown_secs: u64, } #[derive(Debug, Config)] diff --git a/bobbin/crates/bobbin/src/main.rs b/bobbin/crates/bobbin/src/main.rs index ee20123aa..9646c59e4 100644 --- a/bobbin/crates/bobbin/src/main.rs +++ b/bobbin/crates/bobbin/src/main.rs @@ -12,7 +12,7 @@ use bobbin_edge_index::{ use bobbin_ingest::{ IngestConfig, IngestRuntime, RepoIdResolver, WarmingBuffer, run as run_ingest, }; -use bobbin_knot_proxy::MirrorProxy; +use bobbin_knot_proxy::{FailureThreshold, MirrorProxy}; use bobbin_record_lru::{CacheCapacity, LruRecordStore, RecordStore}; use bobbin_resolver::{HydrantClient, IdentityResolver}; use bobbin_runtime::{ @@ -256,11 +256,23 @@ async fn run(cfg: BobbinConfig) -> anyhow::Result<()> { limiter: limiter.clone(), budget, }); + let breaker_threshold = FailureThreshold::new(cfg.mirror.breaker_threshold) + .context("mirror.breaker_threshold")?; + let breaker_cooldown = Duration::from_secs(cfg.mirror.breaker_cooldown_secs); let mirror = cfg .mirror .url .as_ref() - .map(|url| MirrorProxy::new(url, clock.clone(), hasher.clone()).map(Arc::new)) + .map(|url| { + MirrorProxy::with_breaker( + url, + clock.clone(), + hasher.clone(), + breaker_threshold, + breaker_cooldown, + ) + .map(Arc::new) + }) .transpose() .context("mirror.url")?; match mirror.as_ref() { diff --git a/bobbin/crates/knot-proxy/src/mirror.rs b/bobbin/crates/knot-proxy/src/mirror.rs index 6a0a27fac..ab1c1f479 100644 --- a/bobbin/crates/knot-proxy/src/mirror.rs +++ b/bobbin/crates/knot-proxy/src/mirror.rs @@ -37,6 +37,23 @@ impl MirrorProxy { url: &Url, clock: Arc, hasher: RuntimeHasher, + ) -> Result { + Self::with_breaker( + url, + clock, + hasher, + FailureThreshold::new(3).expect("nonzero literal"), + KnotProxyConfig::default().cooldown, + ) + } + + /// `failure_threshold` failures in a row stop requests to the mirror for `cooldown` + pub fn with_breaker( + url: &Url, + clock: Arc, + hasher: RuntimeHasher, + failure_threshold: FailureThreshold, + cooldown: Duration, ) -> Result { let host = KnotHost::parse(url.as_str())?; match beyond_origin(url) { @@ -46,8 +63,8 @@ impl MirrorProxy { KnotProxyConfig { allow_private_hosts: true, require_https: false, - failure_threshold: FailureThreshold::new(3).expect("nonzero literal"), - ..KnotProxyConfig::default() + failure_threshold, + cooldown, }, MIRROR_HTTP, clock, diff --git a/bobbin/example.toml b/bobbin/example.toml index 6e238afd9..2de46f532 100644 --- a/bobbin/example.toml +++ b/bobbin/example.toml @@ -187,6 +187,21 @@ # Can also be specified via environment variable `BOBBIN_MIRROR_URL`. #url = +# failures in a row before requests to the mirror stop for the cooldown +# and answer `knot circuit breaker open` straight away. +# +# Can also be specified via environment variable `BOBBIN_MIRROR_BREAKER_THRESHOLD`. +# +# Default value: 3 +#breaker_threshold = 3 + +# seconds requests to the mirror stay stopped after the breaker opens. +# +# Can also be specified via environment variable `BOBBIN_MIRROR_BREAKER_COOLDOWN_SECS`. +# +# Default value: 30 +#breaker_cooldown_secs = 30 + [log] # Log emitter format. `text` produces human-readable output for local # development. `json` emits one structured object per line for log diff --git a/docs/src/content/docs/reference/bobbin.md b/docs/src/content/docs/reference/bobbin.md index 8538be9d5..cf0a7b9cd 100644 --- a/docs/src/content/docs/reference/bobbin.md +++ b/docs/src/content/docs/reference/bobbin.md @@ -64,6 +64,8 @@ did = "did:web:api.example.com" | `codesearch.zoekt_url` | `BOBBIN_CODESEARCH_ZOEKT_URL` | unset | zoekt-webserver origin. Unset disables `searchCode`. | | `codesearch.zoekt_auth` | `BOBBIN_CODESEARCH_ZOEKT_AUTH` | unset | `user:pass` for zoekt. | | `mirror.url` | `BOBBIN_MIRROR_URL` | unset | Gitmirror origin. Unset disables git endpoints. | +| `mirror.breaker_threshold` | `BOBBIN_MIRROR_BREAKER_THRESHOLD` | 3 | Failures in a row before requests to the mirror stop for the cooldown. | +| `mirror.breaker_cooldown_secs` | `BOBBIN_MIRROR_BREAKER_COOLDOWN_SECS` | 30 | Seconds requests to the mirror stay stopped after the breaker opens. | | `pocket.url` | `BOBBIN_POCKET_URL` | unset | Pocket origin. Unset disables preference endpoints. Missing from `example.toml`. | | `log.format` | `BOBBIN_LOG_FORMAT` | `text` | `text` or `json`. | | `log.filter` | `BOBBIN_LOG` | `info` | Log filter directive. | -- 2.54.0