Could use some help understanding error handling
Opened this issue · 2 comments
I was kicking around some code with a friend last night and we were running into a couple of different errors while using your library.
Here's the relevant fragment of the program: https://github.com/bitemyapp/my-limes/blob/master/src/main.rs#L58-L81
I broke out that big dirty manual loop to try to poke at how the CursorIter
et al. worked. I have a few questions:
-
Does CursorIter bump the page numbers forward when an error is received?
-
If not, can I just sleep until the epoch timestamp Twitter returns and re-attempt a manual call?
-
If it does, should I clone the CursorIter and hold onto the previous one before
call
'ing to handle potential errors? -
Does the iteration API itself do anything to handle errors like
RateLimit
? It didn't seem like it. -
Is it kosher to
core.run
the futures returned by the cursoriter/etc. in a loop?
Sorry for bothering you but it seemed like it'd be best to ask you directly as I thought there must be something I didn't understand in your design intent WRT handling error conditions.
Thank you for your time!
I noticed you posted this on reddit (blame/thank @Havvy for linking that thread to me on IRC), here's what i posted in reply there:
Oh no, sorry for not getting back to y'all! I haven't had a lot of energy recently for rust stuff so i haven't been able to get to your questions. Here's what i can tell you offhand, though:
CursorIter
will only change the cursor references when it successfully receives a page. However, keep in mind that it will also only update its own cursor references in theStream
implementation. If you're handling the calls manually like that, you'll need to look atresp.response.next_cursor
instead offollowers_cursor.next_cursor
.- I believe the idea behind Twitter returning the timestamp like that is that you can sleep to that point and be fine. IIRC that timestamp is in UTC but otherwise that's the intended purpose.
- (Looking at it again, it looks like i don't have
Clone
implemented forCursorIter
! I'm not sure whether i can just derive it, though, since it holds the hyper Response, but your idea there won't work, sadly.) - The
Stream
implementation basically just bails when it encounters an error, doing no processing and instead passing it on up the chain immediately. It kinda made the transition fromIterator
toStream
kinda poorly, because when the stream returns an error it's basically gone. Your best bet it to do what you wound up doing: don't use theStream
at all, and instead manage the cursor handles manually and usecall()
. Looking back at this, it's incredibly unfortunate and i should probably rework it somehow. IIRC a forthcoming release offutures
changes how futures and streams deal with errors? Maybe i can tap into that whenever that comes around. - As far as i can tell, it's totally fine to lean on
core.run
like that. What that's doing is starting the future in the reactor and sleeping your thread whenever it decides to suspend its task. Thanks to how hyper and tokio are set up, that basically means that your thread is blocking on the network call, just like it were a synchronous call. It's not that great if this is in the middle of a big application and you need to deal with multiple threads' worth of Futures, but i use it in all the examples because it's the way to turn async code into sync code.
egg-mode
's model of error handling is "as soon as i get an error, wrap it up and pass it on". As far as the types and stuff, that error enum was decided upon before failure
and error-chain
were a thing, so it's probably not the most idiomatic any more. This habit of bailing immediately has some sharp corners like the aforementioned Stream
implementations. To be honest, i'm not totally sure the best way around it from a library design perspective, but i also haven't worked on egg-mode
in months, so i bet there's something i'm missing.
I have been using this crate as a way to learn rust, and have been quite confused about how to handle rate limit errors.
It seems to me from reading this that if you want to handle the basic cases of errors, like ratelimitstatus, then streaming it will result in an error, with no way to start again from the point at which you encountered the error.
Now that some time has passed since this issue, would you say it is worth looking at this issue again? Feels like a shame to leave this hanging