Skip to main content

TerminateOnDrop

Struct TerminateOnDrop 

Source
pub struct TerminateOnDrop<Stdout: OutputStream, Stderr: OutputStream = Stdout> { /* private fields */ }
Expand description

A wrapper that automatically terminates a process when dropped.

§Safety Requirements

WARNING: This type requires a multithreaded tokio runtime to function correctly!

§Usage Guidelines

This type should only be used when:

  • Your code is running in a multithreaded tokio runtime.
  • Automatic process cleanup on drop is absolutely necessary.

Instead of relying on automatic termination, prefer these safer approaches:

  1. Manual process termination using ProcessHandle::terminate
  2. Awaiting process completion using ProcessHandle::wait_for_completion
  3. Awaiting process completion or performing an explicit termination using ProcessHandle::wait_for_completion_or_terminate

§Implementation Details

The drop implementation tries to terminate the process if it was neither awaited nor terminated before being dropped. If checking the current process state fails, it still attempts best-effort termination. If termination fails, a panic is raised.

Methods from Deref<Target = ProcessHandle<Stdout, Stderr>>§

Source

pub fn must_be_terminated(&mut self)

Sets a panic-on-drop mechanism for this ProcessHandle.

This method enables a safeguard that ensures that the process represented by this ProcessHandle is properly terminated or awaited before being dropped. If must_be_terminated is set and the ProcessHandle is dropped without successfully terminating, killing, waiting for, or explicitly detaching the process, an intentional panic will occur to prevent silent failure-states, ensuring that system resources are handled correctly.

You typically do not need to call this, as every ProcessHandle is marked by default. Call must_not_be_terminated to clear this safeguard to explicitly allow dropping the process without terminating it. Calling this method while the safeguard is already enabled is safe and has no effect beyond keeping the handle armed.

§Panic

If the ProcessHandle is dropped without being awaited or terminated successfully after calling this method, a panic will occur with a descriptive message to inform about the incorrect usage.

Source

pub fn must_not_be_terminated(&mut self)

Disables the kill/panic-on-drop safeguards for this handle.

Dropping the handle after calling this method will no longer signal, kill, or panic. However, this does not keep the library-owned stdio pipes alive. If the child still depends on stdin, stdout, or stderr being open, dropping the handle may still affect it.

Use plain tokio::process::Command directly when you need a child process that can outlive the original handle without depending on captured stdio pipes.

Source

pub async fn wait_for_completion_with_output( &mut self, timeout: Duration, output_options: LineOutputOptions, ) -> Result<WaitForCompletionResult<ProcessOutput<CollectedLines>>, WaitWithOutputError>

Waits for the process to complete while collecting line output.

Collectors are attached when this method is called. If the stream was configured with .no_replay(), output produced before attachment may be discarded; configure replay before spawning when startup output must be included. Any still-open stdin handle is closed before the terminal wait begins, matching tokio::process::Child::wait. timeout bounds both process completion and stdout/stderr collection.

§Errors

Returns WaitWithOutputError if waiting for the process or collecting output fails after the process completes. Process timeout is returned as WaitForCompletionResult::Timeout.

Source

pub async fn wait_for_completion_with_raw_output( &mut self, timeout: Duration, output_options: RawOutputOptions, ) -> Result<WaitForCompletionResult<ProcessOutput<CollectedBytes>>, WaitWithOutputError>

Waits for the process to complete while collecting raw byte output.

Any still-open stdin handle is closed before the terminal wait begins, matching tokio::process::Child::wait. timeout bounds both process completion and stdout/stderr collection.

§Errors

Returns WaitWithOutputError if waiting for the process or collecting output fails after the process completes. Process timeout is returned as WaitForCompletionResult::Timeout.

Source

pub async fn wait_for_completion_with_output_or_terminate( &mut self, options: WaitForCompletionOrTerminateOptions, output_options: LineOutputOptions, ) -> Result<WaitForCompletionOrTerminateResult<ProcessOutput<CollectedLines>>, WaitWithOutputError>

Waits for completion within wait_timeout, terminating the process if needed, while collecting line output.

Any still-open stdin handle is closed before the initial terminal wait begins, matching tokio::process::Child::wait. Output collection is bounded by wait_timeout + interrupt_timeout + terminate_timeout, plus a fixed 3-second post-kill confirmation wait when force-kill fallback is required.

§Errors

Returns WaitWithOutputError if waiting, termination, or output collection fails. Timeout-triggered cleanup success is returned as WaitForCompletionOrTerminateResult::TerminatedAfterTimeout.

Source

pub async fn wait_for_completion_with_raw_output_or_terminate( &mut self, options: WaitForCompletionOrTerminateOptions, output_options: RawOutputOptions, ) -> Result<WaitForCompletionOrTerminateResult<ProcessOutput<CollectedBytes>>, WaitWithOutputError>

Waits for completion within wait_timeout, terminating the process if needed, while collecting raw byte output.

Any still-open stdin handle is closed before the initial terminal wait begins, matching tokio::process::Child::wait. Output collection is bounded by wait_timeout + interrupt_timeout + terminate_timeout, plus a fixed 3-second post-kill confirmation wait when force-kill fallback is required.

§Errors

Returns WaitWithOutputError if waiting, termination, or output collection fails. Timeout-triggered cleanup success is returned as WaitForCompletionOrTerminateResult::TerminatedAfterTimeout.

Source

pub fn send_interrupt_signal(&mut self) -> Result<(), TerminationError>

Manually send an interrupt signal to this process.

This is SIGINT on Unix and the targetable graceful Windows equivalent (CTRL_BREAK_EVENT) on Windows.

If the process has already exited, this reaps it and returns Ok(()) instead of attempting to signal a stale PID or process group. If the signal send fails because the child exited after the preflight check, this also reaps it and returns Ok(()).

Prefer to call terminate instead, if you want to make sure this process is terminated.

§Errors

Returns TerminationError if the process status could not be checked or if the platform signal could not be sent.

Source

pub fn send_terminate_signal(&mut self) -> Result<(), TerminationError>

Manually send a termination signal to this process.

This is SIGTERM on Unix and CTRL_BREAK_EVENT on Windows.

If the process has already exited, this reaps it and returns Ok(()) instead of attempting to signal a stale PID or process group. If the signal send fails because the child exited after the preflight check, this also reaps it and returns Ok(()).

Prefer to call terminate instead, if you want to make sure this process is terminated.

§Errors

Returns TerminationError if the process status could not be checked or if the platform signal could not be sent.

Source

pub async fn terminate( &mut self, interrupt_timeout: Duration, terminate_timeout: Duration, ) -> Result<ExitStatus, TerminationError>

Terminates this process by sending platform graceful shutdown signals first, then killing the process if it does not complete after receiving them.

On Unix this means SIGINT, then SIGTERM, then SIGKILL. On Windows, targeted CTRL_C_EVENT delivery is not supported for child process groups, so both graceful phases use CTRL_BREAK_EVENT before falling back to TerminateProcess. After the graceful phases time out, termination performs one additional fixed 3-second wait for the force-kill result.

When this method returns Ok, the process has reached a terminal state and this handle’s drop cleanup and panic guards are disarmed, so the handle can be dropped safely afterward.

If this method returns Err, or if the returned future is canceled before completion, the guards remain armed. Dropping the handle will still attempt best-effort cleanup and panic unless the process is later successfully awaited, terminated, killed, or explicitly detached with ProcessHandle::must_not_be_terminated.

§Errors

Returns TerminationError if signalling or waiting for process termination fails.

Source

pub async fn kill(&mut self) -> Result<(), TerminationError>

Forces the process to exit. Most users should call ProcessHandle::terminate instead.

This is equivalent to sending SIGKILL on Unix or calling TerminateProcess on Windows, followed by wait. Any still-open stdin handle is closed before Tokio performs that kill-and-wait sequence, matching tokio::process::Child::kill semantics. A successful call waits for the child to exit and disarms the drop cleanup and panic guards, so the handle can be dropped safely afterward.

§Errors

Returns TerminationError if Tokio cannot kill or wait for the child process.

Source

pub async fn wait_for_completion( &mut self, timeout: Duration, ) -> Result<WaitForCompletionResult, WaitError>

Wait for this process to run to completion within timeout.

Any still-open stdin handle is closed before waiting begins, matching tokio::process::Child::wait and helping avoid deadlocks where the child is waiting for input while the parent is waiting for exit.

If the timeout is reached before the process terminated, a timeout outcome is returned and the process keeps running without being signalled or killed. Its stdin has still been closed before the wait started. Use ProcessHandle::wait_for_completion_or_terminate if you want immediate termination.

This does not provide the processes output. Use ProcessHandle::stdout and ProcessHandle::stderr to inspect, watch over, or capture the process output.

§Errors

Returns WaitError if waiting for the process fails.

Source

pub async fn wait_for_completion_or_terminate( &mut self, options: WaitForCompletionOrTerminateOptions, ) -> Result<WaitForCompletionOrTerminateResult, WaitOrTerminateError>

Wait for this process to run to completion within timeout.

Any still-open stdin handle is closed before the initial wait begins, matching tokio::process::Child::wait.

If the timeout is reached before the process terminated normally, external termination is forced through ProcessHandle::terminate and a WaitForCompletionOrTerminateResult::TerminatedAfterTimeout outcome is returned when cleanup succeeds. If waiting fails for a non-timeout reason, cleanup termination is still attempted and the original wait failure is preserved in the returned error. Total wall-clock time can exceed wait_timeout + interrupt_timeout + terminate_timeout by one additional fixed 3-second wait when force-kill fallback is required.

§Errors

Returns WaitOrTerminateError if waiting fails or if timeout-triggered termination is required and then fails.

Source

pub fn stdin(&mut self) -> &mut Stdin

Returns a mutable reference to the (potentially already closed) stdin stream.

Use this to write data to the child process’s stdin. The stdin stream implements tokio::io::AsyncWrite, allowing you to use methods like write_all() and flush().

§Example
    AutoName, DEFAULT_MAX_BUFFERED_CHUNKS, DEFAULT_READ_CHUNK_SIZE, Process,
};
// The stream backend does not make a difference here.
let mut process = Process::new(Command::new("cat"))
    .name(AutoName::program_only())
    .stdout_and_stderr(|stream| {
        stream
            .broadcast()
            .best_effort_delivery()
            .no_replay()
            .read_chunk_size(DEFAULT_READ_CHUNK_SIZE)
            .max_buffered_chunks(DEFAULT_MAX_BUFFERED_CHUNKS)
    })
    .spawn()
    .unwrap();

// Write to stdin.
if let Some(stdin) = process.stdin().as_mut() {
    stdin.write_all(b"Hello, process!\n").await.unwrap();
    stdin.flush().await.unwrap();
}

// Close stdin to signal EOF.
process.stdin().close();
Source

pub fn stdout(&self) -> &Stdout

Returns a reference to the stdout stream.

For BroadcastOutputStream, this allows creating multiple concurrent consumers. For SingleSubscriberOutputStream, only one active consumer can exist at a time (concurrent attempts will panic with a helpful error message).

Source

pub fn stderr(&self) -> &Stderr

Returns a reference to the stderr stream.

For BroadcastOutputStream, this allows creating multiple concurrent consumers. For SingleSubscriberOutputStream, only one active consumer can exist at a time (concurrent attempts will panic with a helpful error message).

Source

pub fn id(&self) -> Option<u32>

Returns the OS process ID if the process hasn’t exited yet.

Once this process has been polled to completion this will return None.

Source

pub fn is_running(&mut self) -> RunningState

Checks if the process is currently running.

Returns RunningState::Running if the process is still running, RunningState::Terminated if it has exited, or RunningState::Uncertain if the state could not be determined. Each call re-runs the underlying try_wait, so a transient probing failure observed once does not become permanent.

This is a pure status query: it does not disarm the drop-cleanup or panic guards, even when it observes that the process has exited. A handle whose status reads RunningState::Terminated still panics on drop until one of the lifecycle methods has closed it. Use Self::wait_for_completion, Self::terminate, or Self::kill to close the lifecycle through a successful terminal call, or call Self::must_not_be_terminated explicitly to detach the handle without termination.

Trait Implementations§

Source§

impl<Stdout: Debug + OutputStream, Stderr: Debug + OutputStream> Debug for TerminateOnDrop<Stdout, Stderr>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<Stdout, Stderr> Deref for TerminateOnDrop<Stdout, Stderr>
where Stdout: OutputStream, Stderr: OutputStream,

Source§

type Target = ProcessHandle<Stdout, Stderr>

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Self::Target

Dereferences the value.
Source§

impl<Stdout, Stderr> DerefMut for TerminateOnDrop<Stdout, Stderr>
where Stdout: OutputStream, Stderr: OutputStream,

Source§

fn deref_mut(&mut self) -> &mut Self::Target

Mutably dereferences the value.
Source§

impl<Stdout, Stderr> Drop for TerminateOnDrop<Stdout, Stderr>
where Stdout: OutputStream, Stderr: OutputStream,

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

§

impl<Stdout, Stderr> Freeze for TerminateOnDrop<Stdout, Stderr>
where Stdout: Freeze, Stderr: Freeze,

§

impl<Stdout, Stderr = Stdout> !RefUnwindSafe for TerminateOnDrop<Stdout, Stderr>

§

impl<Stdout, Stderr> Send for TerminateOnDrop<Stdout, Stderr>
where Stdout: Send, Stderr: Send,

§

impl<Stdout, Stderr> Sync for TerminateOnDrop<Stdout, Stderr>
where Stdout: Sync, Stderr: Sync,

§

impl<Stdout, Stderr> Unpin for TerminateOnDrop<Stdout, Stderr>
where Stdout: Unpin, Stderr: Unpin,

§

impl<Stdout, Stderr> UnsafeUnpin for TerminateOnDrop<Stdout, Stderr>
where Stdout: UnsafeUnpin, Stderr: UnsafeUnpin,

§

impl<Stdout, Stderr = Stdout> !UnwindSafe for TerminateOnDrop<Stdout, Stderr>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> Sink for T
where T: Send + 'static,