proc_heim/process/
scoped_process_handle.rs

1use std::time::Duration;
2use std::{fmt::Debug, sync::Arc};
3
4use crate::manager::{
5    GetLogsError, GetProcessInfoError, KillProcessError, LogsQuery, ProcessId, ProcessInfo,
6    ReadMessageError, ReceiveMessageError, WriteMessageError,
7};
8
9use tokio::task::JoinHandle;
10use tokio_stream::Stream;
11
12use super::message::Message;
13use super::ProcessHandle;
14
15/// A wrapper around [`ProcessHandle`] that kills the associated child process, when the last instance of the handle is dropped.
16///
17/// There is no guarantee that the process will be killed immediately.
18///
19/// The handle can be created also by calling [`ProcessManagerHandle::spawn_with_scoped_handle`](method@crate::process::ProcessManagerHandle::spawn_with_scoped_handle).
20#[derive(Clone, Debug)]
21pub struct ScopedProcessHandle {
22    handle: ProcessHandle,
23    instance_counter: Arc<()>,
24}
25
26impl ScopedProcessHandle {
27    /// Creates a new `ScopedProcessHandle` from given process handle.
28    pub fn new(handle: ProcessHandle) -> Self {
29        Self {
30            handle,
31            instance_counter: Arc::new(()),
32        }
33    }
34
35    /// Returns a process identifier associated with a handle.
36    pub fn id(&self) -> &ProcessId {
37        self.handle.id()
38    }
39
40    /// See [`ProcessManagerHandle::send_message`](method@crate::process::ProcessManagerHandle::send_message) docs.
41    pub async fn send_message<M>(&self, message: M) -> Result<(), WriteMessageError>
42    where
43        M: Into<Message>,
44    {
45        self.handle.send_message(message).await
46    }
47
48    /// See [`ProcessManagerHandle::subscribe_message_stream`](method@crate::process::ProcessManagerHandle::subscribe_message_stream) docs.
49    pub async fn subscribe_message_stream(
50        &self,
51    ) -> Result<impl Stream<Item = Result<Message, ReceiveMessageError>>, ReadMessageError> {
52        self.handle.subscribe_message_stream().await
53    }
54
55    /// See [`ProcessManagerHandle::get_logs_stdout`](method@crate::process::ProcessManagerHandle::get_logs_stdout) docs.
56    pub async fn get_logs_stdout(&self, query: LogsQuery) -> Result<Vec<String>, GetLogsError> {
57        self.handle.get_logs_stdout(query).await
58    }
59
60    /// See [`ProcessManagerHandle::get_logs_stderr`](method@crate::process::ProcessManagerHandle::get_logs_stderr) docs.
61    pub async fn get_logs_stderr(&self, query: LogsQuery) -> Result<Vec<String>, GetLogsError> {
62        self.handle.get_logs_stderr(query).await
63    }
64
65    /// See [`ProcessManagerHandle::get_process_info`](method@crate::process::ProcessManagerHandle::get_process_info) docs.
66    pub async fn get_process_info(&self) -> Result<ProcessInfo, GetProcessInfoError> {
67        self.handle.get_process_info().await
68    }
69
70    /// See [`ProcessManagerHandle::wait`](method@crate::process::ProcessManagerHandle::wait) docs.
71    pub fn wait(
72        &self,
73        poll_interval: Duration,
74    ) -> JoinHandle<Result<ProcessInfo, GetProcessInfoError>> {
75        self.handle.wait(poll_interval)
76    }
77
78    /// See [`ProcessManagerHandle::kill`](method@crate::process::ProcessManagerHandle::kill) docs.
79    pub async fn kill(&self) -> Result<(), KillProcessError> {
80        self.handle.kill().await
81    }
82}
83
84impl Drop for ScopedProcessHandle {
85    fn drop(&mut self) {
86        if Arc::strong_count(&self.instance_counter) == 1
87            && !self.handle.handle.try_kill(*self.id())
88        {
89            let handle = self.handle.clone();
90            tokio::spawn(async move {
91                handle
92                    .handle
93                    .kill_with_timeout(*handle.id(), Duration::from_millis(200))
94                    .await
95            });
96        }
97    }
98}
99
100impl From<ProcessHandle> for ScopedProcessHandle {
101    fn from(handle: ProcessHandle) -> Self {
102        Self::new(handle)
103    }
104}