Skip to content

Commit 2c9556f

Browse files
authored
Merge pull request #3 from chungthuang/chungthuang/fail-child-process-if-no-metadata
Kill child process if parent state cannot be delivered
2 parents f08faf2 + 0c0a92e commit 2c9556f

File tree

1 file changed

+34
-6
lines changed

1 file changed

+34
-6
lines changed

src/lib.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,18 @@ pub mod shutdown;
4949
pub use shutdown::{ShutdownCoordinator, ShutdownHandle, ShutdownSignal};
5050

5151
use crate::lifecycle::LifecycleHandler;
52-
use crate::pipes::{completion_pipes, create_paired_pipes, FdStringExt, PipeMode};
52+
use crate::pipes::{
53+
completion_pipes, create_paired_pipes, CompletionReceiver, CompletionSender, FdStringExt,
54+
PipeMode,
55+
};
5356
use crate::restart_coordination_socket::{
5457
RestartCoordinationSocket, RestartMessage, RestartRequest, RestartResponse,
5558
};
5659
use anyhow::anyhow;
5760
use futures::stream::{Stream, StreamExt};
5861
use std::env;
5962
use std::ffi::OsString;
60-
use std::fs::remove_file;
63+
use std::fs::{remove_file, File as StdFile};
6164
use std::future::Future;
6265
use std::io;
6366
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd};
@@ -92,6 +95,8 @@ pub struct RestartConfig {
9295
pub environment: Vec<(OsString, OsString)>,
9396
/// Receive fine-grained events on the lifecycle of the new process and support data transfer.
9497
pub lifecycle_handler: Box<dyn LifecycleHandler>,
98+
/// Exits early when child process fail to start
99+
pub exit_on_error: bool,
95100
}
96101

97102
impl RestartConfig {
@@ -133,6 +138,7 @@ impl Default for RestartConfig {
133138
coordination_socket_path: Default::default(),
134139
environment: vec![],
135140
lifecycle_handler: Box::new(lifecycle::NullLifecycleHandler),
141+
exit_on_error: true,
136142
}
137143
}
138144
}
@@ -235,7 +241,11 @@ pub fn spawn_restart_task(
235241
return Ok(child);
236242
}
237243
Err(ChildSpawnError::ChildError(e)) => {
238-
log::error!("Restart failed: {}", e);
244+
if settings.exit_on_error {
245+
return Err(anyhow!("Restart failed: {}", e));
246+
} else {
247+
log::error!("Restart failed: {}", e);
248+
}
239249
}
240250
Err(ChildSpawnError::RestartThreadGone) => {
241251
res?;
@@ -406,7 +416,7 @@ async fn spawn_child(
406416
let process_name = args.next().unwrap();
407417

408418
// Create a pipe for the child to notify us on successful startup
409-
let (mut notif_r, notif_w) = completion_pipes()?;
419+
let (notif_r, notif_w) = completion_pipes()?;
410420

411421
// And another pair of pipes to hand over data to the child process.
412422
let (handover_r, handover_w) = create_paired_pipes(PipeMode::ParentWrites)?;
@@ -429,16 +439,34 @@ async fn spawn_child(
429439
});
430440
}
431441
}
432-
let child = cmd.spawn()?;
442+
let mut child = cmd.spawn()?;
443+
444+
if let Err(e) = send_parent_state(lifecycle_handler, notif_r, notif_w, handover_w).await {
445+
if child.kill().is_err() {
446+
log::error!("Child process has already exited. Failed to send parent state: {e:?}");
447+
} else {
448+
log::error!("Killed child process because failed to send parent state: {e:?}");
449+
}
450+
return Err(e);
451+
}
452+
453+
Ok(child)
454+
}
433455

456+
async fn send_parent_state(
457+
lifecycle_handler: &mut dyn LifecycleHandler,
458+
mut notif_r: CompletionReceiver,
459+
notif_w: CompletionSender,
460+
handover_w: StdFile,
461+
) -> io::Result<()> {
434462
lifecycle_handler
435463
.send_to_new_process(Box::pin(File::from(handover_w)))
436464
.await?;
437465

438466
// only the child needs the write end
439467
drop(notif_w);
440468
match notif_r.recv() {
441-
Ok(_) => Ok(child),
469+
Ok(_) => Ok(()),
442470
Err(e) => {
443471
lifecycle_handler.new_process_failed().await;
444472
Err(e)

0 commit comments

Comments
 (0)