From 035a1f531fb70c4b6e662615a2f2bfa7284db076 Mon Sep 17 00:00:00 2001 From: Bryan Stitt Date: Sun, 29 May 2022 14:39:17 +0000 Subject: [PATCH] json errors --- TODO.md | 8 ++++++++ web3-proxy/src/frontend.rs | 21 +++++++++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/TODO.md b/TODO.md index 5d840656..c6d7f10f 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,12 @@ # Todo +- [ ] support websocket clients + - we support websockets for the backends already, but we need them for the frontend too + - [ ] when block subscribers receive blocks, store them in a cache + - [ ] have a /ws endpoint (figure out how to route on / later) + - [ ] ws endpoint shouldn't be that different from the http endpoint + - inspect any jsonrpc errors. if its something like "header not found" or "block with id $x not found" retry on another node (and add a negative score to that server) + - this error seems to happen when we use load balanced rpcs - [x] use redis and redis-cell for rate limits - [ ] if we don't cache errors, then in-flight request caching is going to bottleneck - [x] some production configs are occassionally stuck waiting at 100% cpu @@ -26,6 +33,7 @@ - [ ] add the backend server to the header? - [x] the web3proxyapp object gets cloned for every call. why do we need any arcs inside that? shouldn't they be able to connect to the app's? can we just use static lifetimes - [ ] think more about how multiple rpc tiers should work + - we should have a "backup" tier that is only used when the primary tier has no servers or is multiple blocks behind. we don't want the backup tier taking over all the time. only if the primary tier has fallen behind or gone entirely offline - [ ] if a request gets a socket timeout, try on another server - maybe always try at least two servers in parallel? and then return the first? or only if the first one doesn't respond very quickly? - [ ] incoming rate limiting (by ip or by api key or what?) diff --git a/web3-proxy/src/frontend.rs b/web3-proxy/src/frontend.rs index 6f3a3e54..446ead8f 100644 --- a/web3-proxy/src/frontend.rs +++ b/web3-proxy/src/frontend.rs @@ -56,8 +56,8 @@ async fn proxy_web3_rpc( app: Extension>, ) -> impl IntoResponse { match app.0.proxy_web3_rpc(payload.0).await { - Ok(response) => (StatusCode::OK, serde_json::to_string(&response).unwrap()), - Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, format!("{}", e)), + Ok(response) => (StatusCode::OK, Json(&response)).into_response(), + Err(err) => _handle_anyhow_error(err, None).await.into_response(), } } @@ -78,17 +78,19 @@ async fn status(app: Extension>) -> impl IntoResponse { "num_active_requests": num_active_requests, }); - (StatusCode::INTERNAL_SERVER_ERROR, body.to_string()) + (StatusCode::INTERNAL_SERVER_ERROR, Json(body)) } -/// TODO: pretty 404 page +/// TODO: pretty 404 page? or us a json error fine? async fn handler_404() -> impl IntoResponse { - (StatusCode::NOT_FOUND, "nothing to see here") + let err = anyhow::anyhow!("nothing to see here"); + + _handle_anyhow_error(err, Some(StatusCode::NOT_FOUND)).await } /// handle errors by converting them into something that implements `IntoResponse` /// TODO: use this. i can't get https://docs.rs/axum/latest/axum/error_handling/index.html to work -async fn _handle_anyhow_error(err: anyhow::Error) -> impl IntoResponse { +async fn _handle_anyhow_error(err: anyhow::Error, code: Option) -> impl IntoResponse { let err = format!("{:?}", err); warn!("Responding with error: {}", err); @@ -105,10 +107,9 @@ async fn _handle_anyhow_error(err: anyhow::Error) -> impl IntoResponse { }), }; - ( - StatusCode::INTERNAL_SERVER_ERROR, - serde_json::to_string(&err).unwrap(), - ) + let code = code.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR); + + (code, Json(err)) } // i think we want a custom result type. it has an anyhow result inside. it impl IntoResponse