Files
meilisearch/crates/xtask/src/common/meili_process.rs
2025-08-26 11:13:40 +02:00

145 lines
4.5 KiB
Rust

use std::collections::BTreeMap;
use std::path::Path;
use std::time::Duration;
use anyhow::{bail, Context as _};
use tokio::process::Command as TokioCommand;
use tokio::time;
use crate::common::client::Client;
use crate::common::command::{health_command, run as run_command};
pub async fn kill(mut meilisearch: tokio::process::Child) {
let Some(id) = meilisearch.id() else { return };
match TokioCommand::new("kill").args(["--signal=TERM", &id.to_string()]).spawn() {
Ok(mut cmd) => {
let Err(error) = cmd.wait().await else { return };
tracing::warn!(
error = &error as &dyn std::error::Error,
"while awaiting the Meilisearch server kill"
);
}
Err(error) => {
tracing::warn!(
error = &error as &dyn std::error::Error,
"while terminating Meilisearch server with a kill -s TERM"
);
if let Err(error) = meilisearch.kill().await {
tracing::warn!(
error = &error as &dyn std::error::Error,
"while terminating Meilisearch server"
)
}
return;
}
};
match time::timeout(Duration::from_secs(5), meilisearch.wait()).await {
Ok(_) => (),
Err(_) => {
if let Err(error) = meilisearch.kill().await {
tracing::warn!(
error = &error as &dyn std::error::Error,
"while terminating Meilisearch server"
)
}
}
}
}
#[tracing::instrument]
async fn build() -> anyhow::Result<()> {
let mut command = TokioCommand::new("cargo");
command.arg("build").arg("--release").arg("-p").arg("meilisearch");
command.kill_on_drop(true);
let mut builder = command.spawn().context("error building Meilisearch")?;
if !builder.wait().await.context("could not build Meilisearch")?.success() {
bail!("failed building Meilisearch")
}
Ok(())
}
#[tracing::instrument(skip(client, master_key), fields(workload = _workload))]
pub async fn start(
client: &Client,
master_key: Option<&str>,
extra_cli_args: &[String],
_workload: &str,
binary_path: Option<&Path>,
) -> anyhow::Result<tokio::process::Child> {
delete_db();
let mut command = match binary_path {
Some(binary_path) => tokio::process::Command::new(binary_path),
None => {
build().await?;
let mut command = tokio::process::Command::new("cargo");
command
.arg("run")
.arg("--release")
.arg("-p")
.arg("meilisearch")
.arg("--bin")
.arg("meilisearch")
.arg("--");
command
}
};
command.arg("--db-path").arg("./_xtask_benchmark.ms");
if let Some(master_key) = master_key {
command.arg("--master-key").arg(master_key);
}
command.arg("--experimental-enable-logs-route");
for extra_arg in extra_cli_args.iter() {
command.arg(extra_arg);
}
command.kill_on_drop(true);
let mut meilisearch = command.spawn().context("Error starting Meilisearch")?;
wait_for_health(client, &mut meilisearch).await?;
Ok(meilisearch)
}
async fn wait_for_health(
client: &Client,
meilisearch: &mut tokio::process::Child,
) -> anyhow::Result<()> {
for i in 0..100 {
let res = run_command(client, &health_command(), &BTreeMap::new(), "", false).await;
if res.is_ok() {
// check that this is actually the current Meilisearch instance that answered us
if let Some(exit_code) =
meilisearch.try_wait().context("cannot check Meilisearch server process status")?
{
tracing::error!("Got an health response from a different process");
bail!("Meilisearch server exited early with code {exit_code}");
}
return Ok(());
}
time::sleep(Duration::from_millis(500)).await;
// check whether the Meilisearch instance exited early (cut the wait)
if let Some(exit_code) =
meilisearch.try_wait().context("cannot check Meilisearch server process status")?
{
bail!("Meilisearch server exited early with code {exit_code}");
}
tracing::debug!(attempt = i, "Waiting for Meilisearch to go up");
}
bail!("meilisearch is not responding")
}
async fn delete_db() {
let _ = tokio::fs::remove_dir_all("./_xtask_benchmark.ms").await;
}