feat(local): add restart_node_with_args

This commit is contained in:
andrussal 2026-04-02 08:18:52 +02:00
parent 8700bd5a6c
commit e6d692f4d6
6 changed files with 87 additions and 6 deletions

View File

@ -9,6 +9,14 @@ pub trait NodeControlHandle<E: Application>: Send + Sync {
Err("restart_node not supported by this deployer".into())
}
async fn restart_node_with_args(
&self,
_name: &str,
_args: Vec<String>,
) -> Result<(), DynError> {
Err("restart_node_with_args not supported by this deployer".into())
}
async fn start_node(&self, _name: &str) -> Result<StartedNode<E>, DynError> {
Err("start_node not supported by this deployer".into())
}

View File

@ -343,6 +343,20 @@ pub fn yaml_config_launch_spec<T: Serialize>(
rendered_config_launch_spec(config_yaml.into_bytes(), spec)
}
pub fn build_launch_spec_with_args<E>(
config: &<E as Application>::NodeConfig,
dir: &std::path::Path,
label: &str,
extra_args: &[String],
) -> Result<LaunchSpec, DynError>
where
E: crate::env::LocalDeployerEnv,
{
let mut launch = E::build_launch_spec(config, dir, label)?;
launch.args.extend(extra_args.iter().cloned());
Ok(launch)
}
/// Uses an already rendered text config to build a launch spec for `spec`.
pub fn text_config_launch_spec(
rendered_config: impl Into<Vec<u8>>,

View File

@ -21,7 +21,8 @@ mod tests;
pub use helpers::{
BuiltNodeConfig, LocalNodePorts, LocalPeerNode, LocalProcessSpec, NodeConfigEntry,
build_indexed_http_peers, build_indexed_node_configs, build_local_cluster_node_config,
build_indexed_http_peers, build_indexed_node_configs, build_launch_spec_with_args,
build_local_cluster_node_config,
build_local_peer_nodes, default_yaml_launch_spec, discovered_node_access, preallocate_ports,
reserve_local_node_ports, single_http_node_endpoints, text_config_launch_spec,
text_node_config, yaml_config_launch_spec, yaml_node_config,
@ -506,11 +507,14 @@ pub async fn spawn_node_from_config<E: LocalDeployerEnv>(
keep_tempdir: bool,
persist_dir: Option<&std::path::Path>,
snapshot_dir: Option<&std::path::Path>,
extra_args: &[String],
) -> Result<Node<E>, ProcessSpawnError> {
let extra_args = extra_args.to_vec();
ProcessNode::spawn(
&label,
config,
E::build_launch_spec,
move |config, dir, label| build_launch_spec_with_args::<E>(config, dir, label, &extra_args),
E::node_endpoints,
keep_tempdir,
persist_dir,

View File

@ -70,6 +70,14 @@ impl<E: LocalDeployerEnv> ManualCluster<E> {
Ok(self.nodes.restart_node(name).await?)
}
pub async fn restart_node_with_args(
&self,
name: &str,
args: Vec<String>,
) -> Result<(), ManualClusterError> {
Ok(self.nodes.restart_node_with_args(name, args).await?)
}
pub async fn stop_node(&self, name: &str) -> Result<(), ManualClusterError> {
Ok(self.nodes.stop_node(name).await?)
}
@ -125,6 +133,13 @@ impl<E: LocalDeployerEnv> NodeControlHandle<E> for ManualCluster<E> {
.map_err(|err| err.into())
}
async fn restart_node_with_args(&self, name: &str, args: Vec<String>) -> Result<(), DynError> {
self.nodes
.restart_node_with_args(name, args)
.await
.map_err(|err| err.into())
}
async fn stop_node(&self, name: &str) -> Result<(), DynError> {
self.nodes.stop_node(name).await.map_err(|err| err.into())
}

View File

@ -11,9 +11,9 @@ use thiserror::Error;
use crate::{
env::{
LocalDeployerEnv, Node, build_initial_node_configs, build_node_from_template,
initial_persist_dir, initial_snapshot_dir, node_peer_port, readiness_endpoint_path,
spawn_node_from_config,
LocalDeployerEnv, Node, build_initial_node_configs, build_launch_spec_with_args,
build_node_from_template, initial_persist_dir, initial_snapshot_dir, node_peer_port,
readiness_endpoint_path, spawn_node_from_config,
},
process::ProcessSpawnError,
};
@ -96,6 +96,7 @@ impl<E: LocalDeployerEnv> NodeManager<E> {
keep_tempdir,
persist_dir.as_deref(),
snapshot_dir.as_deref(),
&[],
)
.await?,
);
@ -264,6 +265,7 @@ impl<E: LocalDeployerEnv> NodeManager<E> {
built.config,
options.persist_dir.as_deref(),
options.snapshot_dir.as_deref(),
&[],
)
.await?;
@ -274,9 +276,25 @@ impl<E: LocalDeployerEnv> NodeManager<E> {
}
pub async fn restart_node(&self, name: &str) -> Result<(), NodeManagerError> {
self.restart_node_with_args(name, Vec::new()).await
}
pub async fn restart_node_with_args(
&self,
name: &str,
args: Vec<String>,
) -> Result<(), NodeManagerError> {
let (index, mut node) = self.take_node(name)?;
if let Err(source) = node.restart().await {
let launch = build_launch_spec_with_args::<E>(
node.config(),
node.working_dir(),
name,
&args,
)
.map_err(|source| NodeManagerError::Config { source })?;
if let Err(source) = node.restart_with_launch(launch).await {
self.put_node_back(index, node);
return Err(NodeManagerError::Restart {
@ -305,6 +323,7 @@ impl<E: LocalDeployerEnv> NodeManager<E> {
config: <E as Application>::NodeConfig,
persist_dir: Option<&std::path::Path>,
snapshot_dir: Option<&std::path::Path>,
extra_args: &[String],
) -> Result<E::NodeClient, NodeManagerError> {
let node = spawn_node_from_config::<E>(
node_name.to_string(),
@ -312,6 +331,7 @@ impl<E: LocalDeployerEnv> NodeManager<E> {
self.keep_tempdir,
persist_dir,
snapshot_dir,
extra_args,
)
.await
.map_err(|source| NodeManagerError::Spawn {
@ -444,6 +464,12 @@ impl<E: LocalDeployerEnv> NodeControlHandle<E> for NodeManager<E> {
self.restart_node(name).await.map_err(|err| err.into())
}
async fn restart_node_with_args(&self, name: &str, args: Vec<String>) -> Result<(), DynError> {
self.restart_node_with_args(name, args)
.await
.map_err(|err| err.into())
}
async fn stop_node(&self, name: &str) -> Result<(), DynError> {
self.stop_node(name).await.map_err(|err| err.into())
}

View File

@ -168,6 +168,10 @@ impl<Config: Clone + Send + Sync + 'static, Client: Clone + Send + Sync + 'stati
&self.endpoints
}
pub fn working_dir(&self) -> &Path {
self.tempdir.path()
}
pub fn pid(&self) -> u32 {
self.child.id().unwrap_or_default()
}
@ -255,6 +259,16 @@ impl<Config: Clone + Send + Sync + 'static, Client: Clone + Send + Sync + 'stati
Ok(())
}
pub async fn restart_with_launch(
&mut self,
launch: LaunchSpec,
) -> Result<(), ProcessSpawnError> {
self.stop_child().await?;
self.launch = launch;
self.child = self.spawn_child().await?;
Ok(())
}
pub async fn stop(&mut self) {
let _ = self.stop_child().await;
}