Fix clippy warnings, improve test robustness, and clean up proxy code
- task_pruner: use poison-aware lock recovery (unwrap_or_else) for GAUGE_LOCK - task_pruner: add spawn_pruner lifecycle tests (run+stop, drop+stop) - proxy/client: remove unused timeout_ms field, suppress dead_code on preflight_url - proxy/search: fix serde rename for rankingScore field - proxy/indexes: fix clippy unnecessary_lazy_evaluations warning Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
17d02b97f8
commit
de1f37c8b3
6 changed files with 51 additions and 13 deletions
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
|||
483f821dc14b795fd5b7f94a5343dc8bf08dd4d6
|
||||
17d02b97f8fe4c6aeb1f2c01895ad20872cf3efd
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ mod tests {
|
|||
/// next pruner cycle drops all 10k.
|
||||
#[test]
|
||||
fn pruner_deletes_10k_old_terminal_tasks() {
|
||||
let _lock = GAUGE_LOCK.lock().unwrap();
|
||||
let _lock = GAUGE_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let store = test_store();
|
||||
let eight_days_ms: i64 = 8 * 24 * 3600 * 1000;
|
||||
let old_time = now() - eight_days_ms;
|
||||
|
|
@ -260,6 +260,7 @@ mod tests {
|
|||
/// Acceptance: A single in-flight `processing` task at created_at = now - 10d is preserved.
|
||||
#[test]
|
||||
fn pruner_preserves_processing_tasks() {
|
||||
let _lock = GAUGE_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let store = test_store();
|
||||
let ten_days_ms: i64 = 10 * 24 * 3600 * 1000;
|
||||
let old_time = now() - ten_days_ms;
|
||||
|
|
@ -286,6 +287,7 @@ mod tests {
|
|||
/// Acceptance: Pruner advisory lock prevents two instances pruning simultaneously.
|
||||
#[test]
|
||||
fn advisory_lock_prevents_concurrent_pruning() {
|
||||
let _lock = GAUGE_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let store = test_store();
|
||||
let ten_days_ms: i64 = 10 * 24 * 3600 * 1000;
|
||||
let old_time = now() - ten_days_ms;
|
||||
|
|
@ -317,7 +319,7 @@ mod tests {
|
|||
/// Acceptance: miroir_task_registry_size gauge drops after a prune cycle.
|
||||
#[test]
|
||||
fn gauge_drops_after_prune() {
|
||||
let _lock = GAUGE_LOCK.lock().unwrap();
|
||||
let _lock = GAUGE_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let store = test_store();
|
||||
let ten_days_ms: i64 = 10 * 24 * 3600 * 1000;
|
||||
let old_time = now() - ten_days_ms;
|
||||
|
|
@ -343,6 +345,7 @@ mod tests {
|
|||
/// Test that pruner respects batch_size — multiple iterations needed.
|
||||
#[test]
|
||||
fn pruner_batches_correctly() {
|
||||
let _lock = GAUGE_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let store = test_store();
|
||||
let ten_days_ms: i64 = 10 * 24 * 3600 * 1000;
|
||||
let old_time = now() - ten_days_ms;
|
||||
|
|
@ -358,4 +361,42 @@ mod tests {
|
|||
assert_eq!(deleted, 25); // all deleted via multiple batches
|
||||
assert_eq!(store.task_count().unwrap(), 0);
|
||||
}
|
||||
|
||||
/// Acceptance: spawn_pruner runs in background, PrunerHandle::stop joins cleanly.
|
||||
#[test]
|
||||
fn spawn_pruner_runs_and_stops() {
|
||||
let _lock = GAUGE_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let store = Arc::new(test_store());
|
||||
let ten_days_ms: i64 = 10 * 24 * 3600 * 1000;
|
||||
let old_time = now() - ten_days_ms;
|
||||
|
||||
for i in 0..5 {
|
||||
insert_task(store.as_ref(), &format!("old-{i}"), old_time, "succeeded");
|
||||
}
|
||||
|
||||
let mut cfg = default_cfg();
|
||||
cfg.prune_interval_s = 1;
|
||||
let mut handle = spawn_pruner(store.clone(), cfg);
|
||||
|
||||
// Give the pruner a moment to run at least one cycle
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
handle.stop();
|
||||
|
||||
// Old tasks should be pruned
|
||||
assert_eq!(store.task_count().unwrap(), 0);
|
||||
}
|
||||
|
||||
/// Acceptance: dropping PrunerHandle signals stop and joins.
|
||||
#[test]
|
||||
fn pruner_handle_drop_stops_thread() {
|
||||
let _lock = GAUGE_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let store = Arc::new(test_store());
|
||||
let mut cfg = default_cfg();
|
||||
cfg.prune_interval_s = 600; // long interval so it sleeps in the loop
|
||||
{
|
||||
let _handle = spawn_pruner(store, cfg);
|
||||
// handle dropped here
|
||||
}
|
||||
// Thread should have stopped — if this hangs, the test will time out
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ use std::time::Duration;
|
|||
pub struct HttpClient {
|
||||
client: Client,
|
||||
master_key: String,
|
||||
timeout_ms: u64,
|
||||
}
|
||||
|
||||
impl HttpClient {
|
||||
|
|
@ -22,11 +21,7 @@ impl HttpClient {
|
|||
.build()
|
||||
.expect("Failed to create HTTP client");
|
||||
|
||||
Self {
|
||||
client,
|
||||
master_key,
|
||||
timeout_ms,
|
||||
}
|
||||
Self { client, master_key }
|
||||
}
|
||||
|
||||
/// Build the search URL for a node and index.
|
||||
|
|
@ -35,6 +30,7 @@ impl HttpClient {
|
|||
}
|
||||
|
||||
/// Build the preflight URL for a node and index.
|
||||
#[allow(dead_code)]
|
||||
fn preflight_url(&self, address: &str, index_uid: &str) -> String {
|
||||
format!("{}/indexes/{}/_preflight", address.trim_end_matches('/'), index_uid)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ async fn preflight_handler(
|
|||
let node = config
|
||||
.nodes
|
||||
.first()
|
||||
.ok_or_else(|| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
.ok_or(StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
let client = MeilisearchClient::new(config.node_master_key.clone());
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ struct SearchRequestBody {
|
|||
limit: Option<usize>,
|
||||
filter: Option<Value>,
|
||||
facets: Option<Vec<String>>,
|
||||
rankingScore: Option<bool>,
|
||||
#[serde(rename = "rankingScore")]
|
||||
ranking_score: Option<bool>,
|
||||
#[serde(flatten)]
|
||||
rest: Value,
|
||||
}
|
||||
|
|
@ -107,7 +108,7 @@ async fn search_handler(
|
|||
limit: body.limit.unwrap_or(20),
|
||||
filter: body.filter,
|
||||
facets: body.facets,
|
||||
ranking_score: body.rankingScore.unwrap_or(false),
|
||||
ranking_score: body.ranking_score.unwrap_or(false),
|
||||
body: body.rest,
|
||||
global_idf: None, // Will be populated by dfs_query_then_fetch_search
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue