Как изящно отключить среду выполнения Tokio в ответ на SIGTERM? - PullRequest
0 голосов
/ 24 ноября 2018

У меня есть функция main, в которой я создаю среду выполнения Tokio и запускаю на ней два фьючерса.

use tokio;

fn main() {
    let mut runtime = tokio::runtime::Runtime::new().unwrap();

    runtime.spawn(MyMegaFutureNumberOne {});
    runtime.spawn(MyMegaFutureNumberTwo {});

    // Some code to 'join' them after receiving an OS signal
}

Как получить SIGTERM, дождаться выполнения всех незавершенных задач (NotReady s) и выйти из приложения?

1 Ответ

0 голосов
/ 27 ноября 2018

Работать с сигналами сложно, и было бы слишком сложно объяснить, как обрабатывать все возможные случаи.Реализация сигналов не является стандартной для разных платформ, поэтому мой ответ специфичен для Linux.Если вы хотите быть более кроссплатформенным, используйте функцию POSIX sigaction в сочетании с pause;это даст вам больше контроля.

Один из способов добиться того, что вы хотите, - использовать ящик tokio_signal для перехвата сигналов, например: (пример документа)

extern crate futures;
extern crate tokio;
extern crate tokio_signal;

use futures::prelude::*;
use futures::Stream;
use std::time::{Duration, Instant};
use tokio_signal::unix::{Signal, SIGINT, SIGTERM};

fn main() -> Result<(), Box<::std::error::Error>> {
    let mut runtime = tokio::runtime::Runtime::new()?;

    let sigint = Signal::new(SIGINT).flatten_stream();
    let sigterm = Signal::new(SIGTERM).flatten_stream();

    let stream = sigint.select(sigterm);

    let deadline = tokio::timer::Delay::new(Instant::now() + Duration::from_secs(5))
        .map(|()| println!("5 seconds are over"))
        .map_err(|e| eprintln!("Failed to wait: {}", e));

    runtime.spawn(deadline);

    let (item, _rest) = runtime
        .block_on_all(stream.into_future())
        .map_err(|_| "failed to wait for signals")?;

    let item = item.ok_or("received no signal")?;
    if item == SIGINT {
        println!("received SIGINT");
    } else {
        assert_eq!(item, SIGTERM);
        println!("received SIGTERM");
    }

    Ok(())
}

Эта программа будет ожидать завершения всех текущих задач и будет перехватывать выбранные сигналы.Похоже, что это не работает в Windows, так как мгновенно завершает работу программы.

...