Ждите будущего снова после Токио :: time :: timeout - PullRequest
1 голос
/ 05 апреля 2020

Справочная информация:
У меня есть процесс, использующий tokio::process для порождения дочерних процессов с дескрипторами во время выполнения Tokio.

Он также отвечает за освобождение ресурсов после уничтожения child и, согласно документации ( std :: process :: Child , tokio :: process :: Child ), для этого требуется родительский элемент wait() (или await в tokio) для процесса.

Не все процессы ведут себя одинаково с SIGINT или SIGTERM, поэтому я хотел дать ребенку некоторое время для d ie, прежде чем отправлять SIGKILL.

Желаемое решение:

    pub async fn kill(self) {
        // Close input
        std::mem::drop(self.stdin);

        // Send gracefull signal
        let pid = nix::unistd::Pid::from_raw(self.process.id() as nix::libc::pid_t);
        nix::sys::signal::kill(pid, nix::sys::signal::SIGINT);

        // Give the process time to die gracefully
        if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), self.process).await
        {
            // Kill forcefully
            nix::sys::signal::kill(pid, nix::sys::signal::SIGKILL);
            self.process.await;
        }
    }

Однако выдается эта ошибка:

error[E0382]: use of moved value: `self.process`
  --> src/bin/multi/process.rs:46:13
   |
42 |         if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), self.process).await
   |                                                                                 ------------ value moved here
...
46 |             self.process.await;
   |             ^^^^^^^^^^^^ value used here after move
   |
   = note: move occurs because `self.process` has type `tokio::process::Child`, which does not implement the `Copy` trait

И если я подчиняюсь и удаляю self.process.await, я вижу, что дочерний процесс все еще принимает ресурсы в ps.

Вопрос:
Как я могу await в течение некоторого времени и выполнять действия и await снова, если время истекло?

Примечание:
Я решил свою непосредственную проблему, установив таймер Токио, который всегда отправляет * 10 42 * через две секунды и один self.process.await внизу. Но это решение нежелательно, так как другой процесс может появляться в том же PID во время работы таймера.

Редактировать:
Добавление минимального Воспроизводимый пример ( детская площадка )

async fn delay() {
    for _ in 0..6 {
        tokio::time::delay_for(std::time::Duration::from_millis(500)).await;
        println!("Ping!");
    }
}

async fn runner() {
    let delayer = delay();
    if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), delayer).await {
        println!("Taking more than two seconds");
        delayer.await;
    }
}

1 Ответ

1 голос
/ 05 апреля 2020

Вам нужно было передать изменяемую ссылку. Однако сначала вам нужно закрепить будущее, чтобы его изменчивая ссылка могла реализовать Future. pin_mut реэкспорт из фьючерса ящик - хороший помощник в этом:

use futures::pin_mut;

async fn delay() {
    for _ in 0..6 {
        tokio::time::delay_for(std::time::Duration::from_millis(500)).await;
        println!("Ping!");
    }
}

async fn runner() {
    let delayer = delay();
    pin_mut!(delayer);
    if let Err(_) = tokio::time::timeout(std::time::Duration::from_secs(2), &mut delayer).await {
        println!("Taking more than two seconds");
        delayer.await;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...