(
state: &Rc<RefCell<OpState>>,
f: impl Fn(Arc<DiscordConfig>) -> Fut,
)
| 203 | } |
| 204 | |
| 205 | pub async fn discord_request_retry<T: Send, Fut>( |
| 206 | state: &Rc<RefCell<OpState>>, |
| 207 | f: impl Fn(Arc<DiscordConfig>) -> Fut, |
| 208 | ) -> Result<T, AnyError> |
| 209 | where |
| 210 | Fut: Future<Output = Result<T, AnyError>>, |
| 211 | { |
| 212 | let rt_handle = { |
| 213 | let state = state.borrow(); |
| 214 | let rt_ctx: &RuntimeContext = state.borrow(); |
| 215 | rt_ctx.main_tokio_runtime.clone() |
| 216 | }; |
| 217 | |
| 218 | let mut retry_sleep = Duration::from_secs(1); |
| 219 | let max_sleep = Duration::from_secs(60); |
| 220 | let mut retry_count = 1; |
| 221 | |
| 222 | let res = loop { |
| 223 | let discord_config = { |
| 224 | let state = state.borrow(); |
| 225 | let rt_ctx: &RuntimeContext = state.borrow(); |
| 226 | rt_ctx.discord_config.clone() |
| 227 | }; |
| 228 | |
| 229 | // We run the request on the main botloader tokio runtime, the vm runtime is disposed of on shutdown |
| 230 | // and any futures cancelled, which twilights ratelimit handling does not like |
| 231 | let inner_fut = f(discord_config); |
| 232 | let fut = WrappedFuture { |
| 233 | inner: inner_fut, |
| 234 | rt: rt_handle.clone(), |
| 235 | }; |
| 236 | |
| 237 | let retry_reason = match fut.await { |
| 238 | Ok(v) => break Ok(v), |
| 239 | Err(err) => match err.downcast::<twilight_http::Error>() { |
| 240 | Ok(discord_err) => match discord_err.kind() { |
| 241 | ErrorType::RequestCanceled => "REQUEST_CANCELED", |
| 242 | ErrorType::RequestError => "REQUEST_ERROR", |
| 243 | |
| 244 | // I've disabled this for now, from experience this could lead to requests being processed twice. |
| 245 | // ErrorType::RequestTimedOut => "REQUEST_TIMEOUT", |
| 246 | ErrorType::Response { status, .. } if status.get() == 429 => { |
| 247 | if check_bad_request(state, status.get()).is_err() { |
| 248 | break Err(anyhow::anyhow!( |
| 249 | "Hit maximum number of bad requests within a time period" |
| 250 | )); |
| 251 | } |
| 252 | |
| 253 | "RATELIMIT_429" |
| 254 | } |
| 255 | _ => break Err(handle_discord_error(state, discord_err)), |
| 256 | }, |
| 257 | Err(err) => break Err(err), |
| 258 | }, |
| 259 | }; |
| 260 | tokio::time::sleep(retry_sleep).await; |
| 261 | retry_sleep = retry_sleep * 2; |
| 262 | if retry_sleep > max_sleep { |
no test coverage detected