【问题标题】:reqwest post request freezes after random amount of timereqwest 发布请求在随机时间后冻结
【发布时间】:2022-09-24 05:39:04
【问题描述】:

我两周前开始学习 rust,并且一直在制作这个应用程序来监视日志文件,并将大量信息发送到弹性搜索数据库。

问题是在一定时间后,它会冻结(使用 100% CPU),我不明白为什么。

我已经减少了很多代码来试图找出问题所在,但根据 clion 调试器,它仍然在这条线上冻结

let _response = reqwest::Client::new()
    .post(\"http://127.0.0.1/test.php\")
    .header(\"Content-Type\", \"application/json\")
    .body(\"{\\\"test\\\": true}\")
    .timeout(Duration::from_secs(30))
    .send() // <-- Exactly here
    .await;

它冻结并且不返回任何错误消息。

这是上下文中的代码:

use std::{env};
use std::io::{stdout, Write};
use std::path::Path;
use std::time::Duration;
use logwatcher::{LogWatcher, LogWatcherAction};
use serde_json::{json, Value};
use serde_json::Value::Null;
use tokio;

#[tokio::main]
async fn main() {
    let mut log_watcher = LogWatcher::register(\"/var/log/test.log\").unwrap();
    let mut counter = 0;
    let BULK_SIZE = 500;

    log_watcher.watch(&mut move |line: String| { // This triggers each time a new line is appended to /var/log/test.log
        counter += 1;

        if counter >= BULK_SIZE {
            futures::executor::block_on(async { // This has to be async because log_watcher is not async

                let _response = reqwest::Client::new()
                    .post(\"http://127.0.0.1/test.php\") // <-- This is just for testing, it fails towards the DB too
                    .header(\"Content-Type\", \"application/json\")
                    .body(\"{\\\"test\\\": true}\")
                    .timeout(Duration::from_secs(30))
                    .send() // <-- Freezes here
                    .await;

                if _response.is_ok(){
                    println!(\"Ok\");
                }
            });
            counter = 0;
        }
        LogWatcherAction::None
    });
}

日志文件每分钟获取大约 625 行新行。崩溃发生在大约 5500 - 25000 行之后,或者总体上看起来有点随机。

我怀疑这个问题与LogWatcherreqwestblock_on 或异步混合有关。

有谁知道为什么它会随机冻结?

  • 我不熟悉 log-watcher 的工作原理,但您正在以可能导致问题的方式混合同步和异步操作。如果这是整个应用程序,我可能会建议完全放弃 tokio 和 futures,而只使用 reqwest 的 blocking 客户端(而不是异步客户端)。好吧,我刚刚看到您也提到了与数据库交谈,所以也许没关系。
  • 这是问题的主要要点,整个应用程序有点大。删除 tokio 并在 block_on 中移动异步调用会带来更多问题和挑战 thread \'main\' panicked at \'there is no reactor running, must be called from the context of a Tokio 1.x runtime\'
  • 在 tokio 运行时调用 futures executor 可能不是一个好主意。要在 tokio 中运行同步代码,您可以使用 spawn_blocking(将您的日志观察器循环放在那里)并从那里执行异步代码,使用 tokio::spawn 或通过通道发送数据或使用同步 reqwest 客户端等。
  • 一旦log_watcher.watch( 范围打开,它内部就不再是异步的。我将如何用 spawn_blocking 包装它?因为在log_watcher.watch( 内等待 tokio spawn 是不可能的
  • 好吧,我对代码进行了相当大的更改,将 main 更改为同步而不是异步,并将futures::executor::block_on 替换为 tokio\ 的 block_on 函数。它至少在过去一个小时内没有冻结,目前还无法确认。

标签: http asynchronous rust reqwest


【解决方案1】:

问题确实是因为asynctokioblock_on 的混合,不是直接reqwest。

当将 main 更改为非异步并使用 tokio 作为异步调用的 block_on 而不是 futures::executor::block_on 时,问题得到了解决。

fn main() {
    let mut log_watcher = LogWatcher::register("/var/log/test.log").unwrap();
    let mut counter = 0;
    let BULK_SIZE = 500;

    log_watcher.watch(&mut move |line: String| {
        counter += 1;

        if counter >= BULK_SIZE {
            tokio::runtime::Builder::new_multi_thread()
                .enable_all()
                .build()
                .unwrap()
                .block_on(async {

                    let _response = reqwest::Client::new()
                        .post("http://127.0.0.1/test.php")
                        .header("Content-Type", "application/json")
                        .body("{\"test\": true}")
                        .timeout(Duration::from_secs(30))
                        .send()
                        .await;

                    if _response.is_ok(){
                        println!("Ok");
                    }
            });
            counter = 0;
        }
        LogWatcherAction::None
    });
}

【讨论】:

    猜你喜欢
    • 2022-08-03
    • 1970-01-01
    • 2016-06-17
    • 2020-08-02
    • 1970-01-01
    • 1970-01-01
    • 2016-12-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多