Как запустить ракетный сервер вместе с другими вещами?

#rust-rocket

Вопрос:

В принципе, я хочу, чтобы один процесс обрабатывал несколько вещей одновременно (в частности, я хочу иметь конечную точку http для мониторинга службы, не связанной с http), но, похоже, я попал в ракету в зависимости от времени выполнения tokio для конкретной ракеты, и я не вижу, как это обойти. Я думал о том, чтобы сделать rocket основной точкой входа вместо стандартной tokio и запускать другие вещи из этой среды выполнения, но в целом это кажется неправильным и хрупким, поскольку я мог бы переключать библиотеки. Я думал об использовании hyper и warp, и я несколько уверен, что смогу заставить их работать в этой ситуации, но хочу использовать rocket, как я использую его в другом месте в этом проекте. Я использую версию 0.5-rc01.

Из документов:

 Rocket v0.5 uses the tokio runtime. The runtime is started for you if you use #[launch] or #[rocket::main], but you can still launch() a Rocket instance on a custom-built runtime by not using either attribute.
 

К сожалению, я не могу найти никаких дополнительных объяснений того, какие требования предъявляет эта специально созданная среда выполнения, и никаких примеров, не использующих макросы запуска/main.

Вот упрощенная версия кода, который я пытаюсь использовать:

 #[rocket::get("/ex")]
async fn test() -> amp;'static str {
    "OK"
}

#[tokio::main]
async fn main() {
    tokio::spawn(async {
        let config = Config {
            port: 8001,
            address: std::net::Ipv4Addr::new(127, 0, 0, 1).into(),
            ..Config::debug_default()
        };

        rocket::custom(amp;config)
            .mount("/", rocket::routes![test])
            .launch()
            .await;
    });

    let start = Instant::now();
    let mut interval = interval_at(start, tokio::time::Duration::from_secs(5));

    loop {
        interval.tick().await;
        println!("Other scheduled work");
    }
}
 

Когда я нажимаю CTRL-C, чтобы завершить процесс, выводится следующее:

 ^CWarning: Received SIGINT. Requesting shutdown.
Received shutdown request. Waiting for pending I/O...
Warning: Server failed to shutdown cooperatively.
   >> Server is executing inside of a custom runtime.
   >> Rocket's runtime is `#[rocket::main]` or `#[launch]`.
   >> Refusing to terminate runaway custom runtime.
Other scheduled work
Other scheduled work
Other scheduled work
 

Я нашел эту документацию, объясняющую, что вам нужно «сотрудничать» при завершении работы, если вы используете пользовательскую среду выполнения, но в ней не объясняется, что влечет за собой сотрудничество. Кроме того, запуск чего-либо, кроме ракеты, в порожденном потоке приводит к тому, что CTRL-C убивает процесс, как я обычно ожидал, поэтому я думаю, что это связано именно с ракетой. Что мне нужно сделать, чтобы я действительно мог убить процесс?

Правка: Я сдался и переключился на варп, что было в тысячу раз проще. Мне все равно было бы любопытно узнать, как правильно сделать это с помощью rocket, и я бы попробовал еще раз, если у кого-нибудь есть предложения.

Ответ №1:

Я думаю, вы могли бы просто позволить Rocket позаботиться о запуске вашего tokio runtime:

 #[rocket::main]
async fn main() {
    tokio::spawn(async {
        let start = Instant::now();
        let mut interval = interval_at(start, tokio::time::Duration::from_secs(5));

        loop {
            interval.tick().await;
            println!("Other scheduled work");
        }
    });

    let config = Config {
        port: 8001,
        address: std::net::Ipv4Addr::new(127, 0, 0, 1).into(),
        ..Config::debug_default()
    };

    rocket::custom(amp;config)
        .mount("/", rocket::routes![test])
        .launch()
        .await;
}
 

Ваша собственная дополнительная логика может быть реализована в задаче, которую вы создаете, и ракета запускается обычным способом.