bytesnake / telebot

Write Telegram bots in Rust with Tokio and Futures
Other
212 stars 33 forks source link

Provide a useful example for error handling? #61

Closed Follpvosten closed 5 years ago

Follpvosten commented 5 years ago

With most of the code in the examples, network errors (and also Telegram errors which could be temporary) lead to a panic:

There was an error fetching the content                                                                                                                                                           
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ()', src/libcore/result.rs:1009:5

Telegram server responsed with an error                                                                                                                                                           
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ()', src/libcore/result.rs:1009:5

There is this example, which shows how to handle custom errors generated by the user in .then().

But how would I go about handling the errors above?

I have a pretty simple setup using get_stream(): https://gitlab.com/Follpvosten/markov-bot/blob/master/src/bin/markov-bot.rs#L49

Notice the .map_err(|err| println!("{}", err)).

I have tried to work around my problem with that, and I thought it worked, but it actually didn't (it still panics on network problems). I will try to do something like

    .map_err(|err| {                                                                                                                                                                          
            println!("{}", err);                                                                                                                                                                  
            Ok::<(), ()>(())                                                                                                                                                                      
        });

to see if that helps, but I would really like to have some example showing how to do it properly.

Thanks!

bytesnake commented 5 years ago

These errors should be caught for sure, I'm using telebot on a long running server with a constant internet connections therefore I've never encountered them. Can you perhaps add a RUST_BACKTRACE to the error message (in debug mode), then I can find the problem. I'm guessing it is somewhere here

Follpvosten commented 5 years ago

At least the second (Telegram) error can be reproduced quite easily, by attempting to start a second instance of the bot.

Example stacktrace:

Telegram server responsed with an error                                                                                                                                                           
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ()', src/libcore/result.rs:1009:5                                                                                                                                                                                         
stack backtrace:                                                                                                                                                                                  
   0: <std::sys_common::net::LookupHost as core::convert::TryFrom<(&'a str, u16)>>::try_from                                                                                                      
   1: std::time::SystemTime::duration_since                                                                                                                                                       
   2: rust_oom                                                                                                                                                                                    
   3: rust_oom                                                                                                                                                                                    
   4: std::panicking::rust_panic_with_hook                                                                                                                                                        
   5: std::panicking::begin_panic_fmt                                                                                                                                                             
   6: rust_begin_unwind                                                                                                                                                                           
   7: core::panicking::panic_fmt                                                                                                                                                                 
   8: core::result::unwrap_failed                                                                                                                                                                 
   9: <core::result::Result<T, E>>::unwrap                                                                                                                                                        
  10:                                                                                                                                                                                             
  11:                                                                                                                                                                                             
  12: std::panicking::update_panic_count                                                                                                                                                          
  13: __rust_maybe_catch_panic                                                                                                                                                                    
  14: std::rt::lang_start_internal                                                                                                                                                                
  15:                                                                                                                                                                                             
  16:                                                                                                                                                                                             
  17:                                                                                                                                                                                             
  18: <unknown>
bytesnake commented 5 years ago

Thanks I will look into it :smile: this error message is not super helpful, but as you can see some hostname lookup failed, probably the lookup of the telegram server IP address.

Follpvosten commented 5 years ago

It's actually not that, it's a Telegram bot session error (which happens when you try to start two bots with the same token at the same time). The problem isn't really what the error is, but how I would be able to handle it? It doesn't seem to properly be bubbled up/passed to map_err in this case.

bytesnake commented 5 years ago

As I said without the exact location I can only guess, but I just glanced at the code again and this map_err is looking very suspicious https://github.com/bytesnake/telebot/blob/master/src/bot.rs#L352. Perhaps I'll find time later in this day :smile:

bytesnake commented 5 years ago

The resolve_name function was added to acquire the bot name and is called even before the main bot stream function. It will probably fail if you have two bots running simultaneously. Further it just discards the error message, so probably this ..

Follpvosten commented 5 years ago

Since I'm using get_stream() instead of bot.run(), the name is never resolved, so that cannot be the issue as well. Might still be worth checking tho, you're right.

bytesnake commented 5 years ago

Hey, I finally found some time and tested your errors. They are correctly bubbling up in the stream chain, but the handling is a bit more tricky because of failure. I modified the print_everything example to show how to handle those errors correctly in 177c483232a6de8826c4e5a38d84dad9f2aa33e8. Hope this helps you, please comment here again whether this works for you.

bytesnake commented 5 years ago

I still have to figure out the edge case for resolve_name though :smile:

bytesnake commented 5 years ago

Here you go, this is even simpler: e01fc85d04a21c47a35b03ac1baa4d7bc45086f9 (and resolve_name prints the error now)

Follpvosten commented 5 years ago

Thanks! I'm gonna try and see if it works as expected.

In theory, I could restart the stream if it errors out, right? (Or just put a loop around the whole program and restart it on errors)

Because I have semi-predictable networking errors on my server, I'd like my program to just retry when they happen; alternatively, I could just supervise it using an external program, but that would add some complexity beyond a simple cargo run, so I'd prefer an internal way (an "unbreakable" program, you could say).

Follpvosten commented 5 years ago

I just tried it out and it works exactly as intended when setup the way I said (putting a loop {} around creating and running the stream makes it reliably restart on errors). Closed, thanks :smile:

Follpvosten commented 5 years ago

Here's how I implemented it, for reference: https://gitlab.com/Follpvosten/markov-bot/blob/master/src/bin/markov-bot.rs#L53

bytesnake commented 5 years ago

Glad I could help you, I added a small example to show this 7197e27ec10f45f63da5d2b3dcbddb6c0eb081ef.