Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,10 @@ curl 'http://localhost:8080/dependency_edges?from=main&to=my-feature-branch'
}
```

Query endpoints accept `rejectWhenBusy=true` in GET query parameters or `"rejectWhenBusy": true`
in a POST JSON body to return `503` if the selected repository already has an unfinished query.
Omitting it or setting it to `false` preserves normal queueing; other repositories are unaffected.

* `GET /metrics` — returns a JSON snapshot of the instance so callers and monitoring can see its
identity, liveness, and cache size usage without scraping logs. Unlike the query endpoints it is
never gated on readiness, so it still responds on an un-ready or lame-ducked instance (the `ready`
Expand Down Expand Up @@ -387,6 +391,13 @@ curl 'http://localhost:8080/metrics'
}
```

* `GET /metrics/prometheus` — exposes the Prometheus gauge `bazel_diff_compute_slot_demand_avg`
with a `repo` label (`default` for `serve`). It is the time-weighted rolling average of operations
holding or waiting for that repository's workspace lock, not CPU utilization. Enable tracking by
passing `--computeSlotDemandAvgWindow 5s` (or another positive duration). Without this option,
tracking is disabled and the endpoint returns `404`. When enabled it is available regardless of
readiness; the existing JSON `/metrics` is unchanged.

### Serving several repositories

One instance can answer for several git clones. `bazel-diff serve-multi` takes every `serve`
Expand Down
27 changes: 27 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,10 @@ struct ServeArgs {
#[arg(long = "requestTimeout", default_value_t = 0)]
request_timeout: u64,

/// Enable Prometheus workspace demand tracking with this rolling window (e.g. 5s)
#[arg(long = "computeSlotDemandAvgWindow")]
compute_slot_demand_avg_window: Option<String>,

#[arg(long = "cacheDir", value_parser = parse_normalized_path)]
cache_dir: PathBuf,

Expand Down Expand Up @@ -1152,6 +1156,14 @@ impl ServeArgs {
nexus_password: Option<String>,
repositories: Vec<bazel_diff::server::Repository>,
) -> Result<bazel_diff::server::ServerConfig> {
let compute_slot_demand_average_window = self
.compute_slot_demand_avg_window
.as_deref()
.map(bazel_diff::server::parse_duration)
.transpose()?;
if compute_slot_demand_average_window.is_some_and(|window| window.is_zero()) {
bail!("--computeSlotDemandAvgWindow must be greater than 0s");
}
if self.s3_bucket.is_some() && self.s3_endpoint.as_deref().is_some_and(str::is_empty) {
bail!("--s3Endpoint must not be empty");
}
Expand Down Expand Up @@ -1245,6 +1257,7 @@ impl ServeArgs {
nexus_prefix: self.nexus_prefix.clone(),
nexus_credentials,
nexus_ca_cert: self.nexus_ca_cert.clone(),
compute_slot_demand_average_window,
};
bazel_diff::server::validate_partial_graph(&config)?;
bazel_diff::server::repositories(&config)?;
Expand Down Expand Up @@ -1646,6 +1659,8 @@ mod tests {
"--dependencyFingerprint",
"--requestTimeout",
"30",
"--computeSlotDemandAvgWindow",
"1m",
"--cacheMaxAge",
"7d",
"--cacheMaxSize",
Expand Down Expand Up @@ -1673,6 +1688,10 @@ mod tests {
assert!(config.track_deps);
assert!(config.dependency_fingerprint);
assert_eq!(config.request_timeout, Duration::from_secs(30));
assert_eq!(
config.compute_slot_demand_average_window,
Some(Duration::from_secs(60))
);
assert_eq!(config.cache_max_age, Some(Duration::from_secs(7 * 86_400)));
assert_eq!(config.cache_max_size, Some(10 * 1024u64.pow(3)));
assert_eq!(config.cache_max_entries, Some(500));
Expand Down Expand Up @@ -2093,6 +2112,12 @@ mod tests {
args.to_config(false).unwrap()
};
assert!(!serve_config(&[]).dependency_fingerprint);
assert_eq!(serve_config(&[]).compute_slot_demand_average_window, None);
assert_eq!(
serve_config(&["--computeSlotDemandAvgWindow", "5s"])
.compute_slot_demand_average_window,
Some(Duration::from_secs(5))
);
assert!(serve_config(&["--dependencyFingerprint"]).dependency_fingerprint);
assert!(serve_config(&["--dependencyFingerprint=true"]).dependency_fingerprint);
assert!(!serve_config(&["--dependencyFingerprint=false"]).dependency_fingerprint);
Expand All @@ -2105,6 +2130,8 @@ mod tests {
("--cacheMaxAge", "7"),
("--cacheMaxSize", "huge"),
("--cachePruneInterval", "1hour"),
("--computeSlotDemandAvgWindow", "0s"),
("--computeSlotDemandAvgWindow", "invalid"),
] {
let cli = parse(&[
"bazel-diff",
Expand Down
Loading
Loading