Improve typing and errors, clean up

This commit is contained in:
Silas Brack 2026-03-07 15:24:05 +01:00
parent 07490efc28
commit ec408aff29
5 changed files with 205 additions and 22 deletions

View file

@ -5,7 +5,7 @@ use axum::response::{IntoResponse, Response};
use std::sync::Arc;
use crate::db;
use crate::error::AppError;
use crate::error::{AppError, VolumeError};
#[derive(Clone)]
pub struct AppState {
@ -32,11 +32,10 @@ pub async fn put_key(
) -> Result<Response, AppError> {
let target_volumes = crate::hasher::volumes_for_key(&key, &state.volumes, state.replicas);
if target_volumes.len() < state.replicas {
return Err(AppError::VolumeError(format!(
"need {} volumes but only {} available",
state.replicas,
target_volumes.len()
)));
return Err(AppError::InsufficientVolumes {
need: state.replicas,
have: target_volumes.len(),
});
}
// Fan out PUTs to all target volumes concurrently
@ -47,9 +46,11 @@ pub async fn put_key(
let client = state.http.clone();
let data = body.clone();
async move {
let resp = client.put(&url).body(data).send().await.map_err(|e| format!("PUT {url}: {e}"))?;
let resp = client.put(&url).body(data).send().await.map_err(|e| {
VolumeError::Request { url: url.clone(), source: e }
})?;
if !resp.status().is_success() {
return Err(format!("PUT {url}: status {}", resp.status()));
return Err(VolumeError::BadStatus { url, status: resp.status() });
}
Ok(())
}
@ -57,20 +58,20 @@ pub async fn put_key(
handles.push(handle);
}
let mut all_ok = true;
let mut failed = false;
for handle in handles {
if let Err(e) = handle.await.unwrap() {
tracing::error!("PUT to volume failed: {e}");
all_ok = false;
tracing::error!("{e}");
failed = true;
}
}
if !all_ok {
if failed {
// Rollback: best-effort delete from volumes
for vol in &target_volumes {
let _ = state.http.delete(format!("{vol}/{key}")).send().await;
}
return Err(AppError::VolumeError("not all volume writes succeeded".into()));
return Err(AppError::PartialWrite);
}
let size = Some(body.len() as i64);