Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bot stops responding after some time: Only to commands in group chats it seems #978

Open
Bl4d3s opened this issue Nov 29, 2023 · 8 comments
Labels
A-dispatching Area: dispatching updates (`Dispatcher`, repls) K-bug Kind: bug

Comments

@Bl4d3s
Copy link

Bl4d3s commented Nov 29, 2023

I tried this code:

#[tokio::main]
async fn main() {
    pretty_env_logger::init();
    log::info!("Starting command bot...");

    let bot = Bot::new(CONFIG.telegram_token.as_str());

    Command::repl(bot, answer).await;
}

#[derive(BotCommands, Clone)]
#[command(rename_rule = "lowercase", description = "These commands are supported:")]
enum Command {
    #[command(description = "Responds with info required to setup this bot.")]
    Info,
    #[command(description = "display this text.")]
    Help,
    #[command(description = "update a stack. Parameters: env,stack", parse_with = "split")]
    Update { env: String, stack: String },
}

async fn answer(bot: Bot, msg: Message, cmd: Command) -> ResponseResult<()> {
    match cmd {
        Command::Info =>
            bot.send_message(msg.chat.id,
                             if is_allowed_chat(msg.chat.id) {
                                 format!("Your bot is correctly configured to answer to this chat and execute given updates")
                             } else {
                                 format!("Please configure your bot to allow processing of your chat.\nAdd the chat id to the list of allowed ones in the config.toml.\n\nYour chat id: {}", msg.chat.id)
                             }).await?,
        Command::Help => bot.send_message(msg.chat.id, Command::descriptions().to_string()).await?,
        Command::Update { env, stack } => {
            log::info!("Received trigger for {} on {}", stack, env);
            ...
        }
    };

    Ok(())
}

Full code

I expected to see this happen:

Bot works fine, if debugged/started, keeps responding until shutdown.

Instead, this happened:

After some time (differs, between 1h and a day) the bot simply does not respond to any commands anymore.

Happens locally or deployed inside the built Docker.

Restarting the bot fixes the problem for a short time.
What can I do to keep the bot running better?
Any tips to get more debug logs?

One thing I noticed:

Once the internet connection is disconnected/reconnected (happens every day via forced disconnect from my ISP), I get the following errors in the log:

ERROR teloxide::error_handlers > An error from the update listener: Network(reqwest::Error { kind: Request, url: Url { scheme: "https", cannot_be_a_base: false, username: "", password: None, host: Some(Domain("api.telegram.org")), port: None, path: "/token:redacted/GetUpdates", query: None, fragment: None }, source: hyper::Error(Connect, ConnectError("dns error", Os { code: 11001, kind: Uncategorized, message: "Der angegebene Host ist unbekannt." })) })

But the disconnect does not seem to be the problem, if I manually pull my ethernet cable and connect it again after ~2min, the bot works fine.

Meta

  • teloxide version: 0.12.2

Maybe I am using the crate wrong or am missing something?
Any pointers are appreciated, thanks

@Bl4d3s Bl4d3s added the K-bug Kind: bug label Nov 29, 2023
@Bl4d3s
Copy link
Author

Bl4d3s commented Dec 2, 2023

Update:

I implemented now a inline response handler as well:

#[tokio::main]
async fn main() {
    pretty_env_logger::init();
    Config::load_from_file();
    log::info!("Starting command bot...");

    let token = Config::global().telegram_token.to_string();
    let bot = Bot::new(token);
    let command_handler = Update::filter_message().filter_command::<PortainerCommands>().endpoint(answer);
    let inline_handler = Update::filter_inline_query().endpoint(inline_answer);

    let handler = dptree::entry()
        .branch(command_handler)
        .branch(inline_handler);

    Dispatcher::builder(bot, handler)
        .enable_ctrlc_handler()
        .build()
        .dispatch()
        .await;
}

#[derive(BotCommands, Clone)]
#[command(rename_rule = "lowercase", description = "These commands are supported:")]
enum PortainerCommands {
    #[command(description = "Responds with info required to setup this bot.")]
    Info,
    #[command(description = "display this text.")]
    Help,
    #[command(description = "update a stack. Parameters: env,stack", parse_with = "split")]
    Update { env: String, stack: String },
}

async fn answer(bot: Bot, msg: Message, cmd: PortainerCommands) -> ResponseResult<()> {
    let text = match cmd {
        PortainerCommands::Info =>
             if Config::global().is_allowed_chat(msg.chat.id) {
                 format!("Your bot is correctly configured to answer to this chat and execute given updates")
             } else {
                 format!("Please configure your bot to allow processing of your chat.\nAdd the chat id to the list of allowed ones in the config.toml.\n\nYour chat id: {}", msg.chat.id)
             },
        PortainerCommands::Help => PortainerCommands::descriptions().to_string(),
        PortainerCommands::Update { env, stack } => {
            log::info!("Received trigger for {} on {}", stack, env);
            if Config::global().is_allowed_chat(msg.chat.id) {
                let success = trigger_update(env.to_string(), stack.to_string()).await;

                if success.is_none() {
                    log::warn!("Something unexpected happened for {} on {}", stack, env);
                    format!("Something unexpected happened while updating {stack} on environment {env}.")
                } else if success.is_some_and(|success| success) {
                    log::info!("Triggered update for {} on {}", stack, env);
                    format!("Triggered update for {stack} on environment {env}.")
                } else {
                    log::warn!("Failed to update {} on {}", stack, env);
                    format!("Failed to update {stack} on environment {env}.")
                }
            } else {
                log::warn!("Unconfigured chat update");

                format!("Update not allowed from this chat. Please use /info to get instructions to set up this bot.")
            }
        }
    };

    bot.send_message(msg.chat.id, text).await?;

    Ok(())
}



pub async fn inline_answer(bot: Bot, update: InlineQuery) -> Result<(), RequestError> {
    let mut inline_result = get_configured_stacks(update.query.as_str());

    let mut offset = update.offset.parse::<usize>().unwrap_or_default();
    if inline_result.is_empty() {
        inline_result.push(InlineQueryResult::Article(InlineQueryResultArticle::new(
            "1",
            "No stacks configured",
            InputMessageContent::Text(InputMessageContentText::new("No stacks configured")),
        )))
    }
    let mut req_builder = bot.answer_inline_query(update.id, inline_result);
    if offset != 0 {
        req_builder = req_builder.next_offset(offset.to_string());
    }
    req_builder.await?;

    respond(())
}

fn get_configured_stacks(search: &str) -> Vec<InlineQueryResult> {
    let keywords: Vec<&str> = search.split(' ').collect();
    let mut results: Vec<InlineQueryResult> = Vec::new();
    for (environment, stacks) in &Config::global().environments {
        for key in stacks.keys() {
            if keywords.iter().any(|k| key.contains(k)) {
                results.push(InlineQueryResult::Article(InlineQueryResultArticle::new(
                    format!("{}_{}", environment, key),
                    format!("Environment: {}, Stack: {}", environment, key),
                    InputMessageContent::Text(InputMessageContentText::new(format!("/update {} {}", environment, key))),
                )))
            }
        }
    }

    results
}

Now I have the following behaviour:

  1. Bot will still stop responding to commands after some time.
  2. But if I use the inline query that still works.
  3. If I select a search result from the inline query, the body of the result (a command) is posted and correctly executed.
    Afterwards, normal commands are processed again as well (for some time).

This behaviour seems to be restricted to groups, I could not replicate it when talking to the bot in a direct chat.

@Bl4d3s Bl4d3s changed the title Bot stops responding after some time Bot stops responding after some time: Only to commands in group chats it seems Dec 2, 2023
@WaffleLapkin
Copy link
Member

Sadly, I have no idea why this might be happening, if you can minimize the example more, that would be helpful.

@Bl4d3s
Copy link
Author

Bl4d3s commented Jan 4, 2024

I will try to do so next week, will keep you posted.

@Bl4d3s
Copy link
Author

Bl4d3s commented Jan 12, 2024

I managed to create a minimal example: Code here

Environments I could not reproduce the issue:

  • Windows: as exe (directly built without docker)
  • Windows: Built container (as provided in example)

Where it still occurs (where I also noticed it the most with my full bot):

  • Debian server, running Docker/Portainer. There the same docker image behaves just fine for direct chat messages, but not to group commands. Sometimes directly after startup, sometimes after some idle time.

Could there be an issue with how I build the docker container?
The container is in both environments simply part of the default docker network (bridge, ipv4 only).

If you need any further information about my environment, I am happy to provide.

@syrtcevvi
Copy link
Contributor

syrtcevvi commented Jan 12, 2024

At first glance, it seems to me, that polling_default (which is used by the repl fn) settings clash with the proper bot's HTTP client timings (issue 223)

polling_default uses 10 seconds of timeout which is different than ones at default_reqwest_settings

@WaffleLapkin
Copy link
Member

@syrtcevvi polling timeout must be smaller than http client's, which is the case (polling_default = 10s, http = 17s), so I don't think this is the problem...

@WaffleLapkin
Copy link
Member

Just a note: I'm overwhelmed with work, so I'm unlikely to have time to debug this issue anytime soon.

@Bl4d3s
Copy link
Author

Bl4d3s commented Jan 18, 2024

Just a note: I'm overwhelmed with work, so I'm unlikely to have time to debug this issue anytime soon.

No rush, for now it works when chatting directly with the bot, so I have a workaround ^^

@WaffleLapkin WaffleLapkin added the A-dispatching Area: dispatching updates (`Dispatcher`, repls) label Jan 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-dispatching Area: dispatching updates (`Dispatcher`, repls) K-bug Kind: bug
Projects
None yet
Development

No branches or pull requests

3 participants