send the correct content type

This commit is contained in:
Bryan Stitt 2023-05-16 15:27:18 -07:00
parent 525f6d4a34
commit efaaf1bb5f
2 changed files with 46 additions and 13 deletions

@ -38,7 +38,7 @@ pub enum ResponseCacheKey {
pub type ResponseCache = quick_cache_ttl::CacheWithTTL< pub type ResponseCache = quick_cache_ttl::CacheWithTTL<
ResponseCacheKey, ResponseCacheKey,
(StatusCode, axum::body::Bytes), (StatusCode, &'static str, axum::body::Bytes),
UnitWeighter, UnitWeighter,
quick_cache_ttl::DefaultHashBuilder, quick_cache_ttl::DefaultHashBuilder,
>; >;

@ -5,7 +5,12 @@
use super::{ResponseCache, ResponseCacheKey}; use super::{ResponseCache, ResponseCacheKey};
use crate::app::{Web3ProxyApp, APP_USER_AGENT}; use crate::app::{Web3ProxyApp, APP_USER_AGENT};
use axum::{body::Bytes, http::StatusCode, response::IntoResponse, Extension}; use axum::{
body::{Bytes, Full},
http::StatusCode,
response::{IntoResponse, Response},
Extension,
};
use axum_macros::debug_handler; use axum_macros::debug_handler;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use serde_json::json; use serde_json::json;
@ -17,26 +22,40 @@ static HEALTH_NOT_OK: Lazy<Bytes> = Lazy::new(|| Bytes::from(":(\n"));
static BACKUPS_NEEDED_TRUE: Lazy<Bytes> = Lazy::new(|| Bytes::from("true\n")); static BACKUPS_NEEDED_TRUE: Lazy<Bytes> = Lazy::new(|| Bytes::from("true\n"));
static BACKUPS_NEEDED_FALSE: Lazy<Bytes> = Lazy::new(|| Bytes::from("false\n")); static BACKUPS_NEEDED_FALSE: Lazy<Bytes> = Lazy::new(|| Bytes::from("false\n"));
static CONTENT_TYPE_JSON: &str = "application/json";
static CONTENT_TYPE_PLAIN: &str = "text/plain";
/// Health check page for load balancers to use. /// Health check page for load balancers to use.
#[debug_handler] #[debug_handler]
pub async fn health( pub async fn health(
Extension(app): Extension<Arc<Web3ProxyApp>>, Extension(app): Extension<Arc<Web3ProxyApp>>,
Extension(cache): Extension<Arc<ResponseCache>>, Extension(cache): Extension<Arc<ResponseCache>>,
) -> impl IntoResponse { ) -> impl IntoResponse {
cache let (code, content_type, body) = cache
.get_or_insert_async::<Infallible, _>(&ResponseCacheKey::Health, async move { .get_or_insert_async::<Infallible, _>(&ResponseCacheKey::Health, async move {
Ok(_health(app).await) Ok(_health(app).await)
}) })
.await .await
.unwrap();
Response::builder()
.status(code)
.header("content-type", content_type)
.body(Full::from(body))
.unwrap()
} }
// TODO: _health doesn't need to be async, but _quick_cache_ttl needs an async function // TODO: _health doesn't need to be async, but _quick_cache_ttl needs an async function
#[inline] #[inline]
async fn _health(app: Arc<Web3ProxyApp>) -> (StatusCode, Bytes) { async fn _health(app: Arc<Web3ProxyApp>) -> (StatusCode, &'static str, Bytes) {
if app.balanced_rpcs.synced() { if app.balanced_rpcs.synced() {
(StatusCode::OK, HEALTH_OK.clone()) (StatusCode::OK, CONTENT_TYPE_PLAIN, HEALTH_OK.clone())
} else { } else {
(StatusCode::SERVICE_UNAVAILABLE, HEALTH_NOT_OK.clone()) (
StatusCode::SERVICE_UNAVAILABLE,
CONTENT_TYPE_PLAIN,
HEALTH_NOT_OK.clone(),
)
} }
} }
@ -46,15 +65,22 @@ pub async fn backups_needed(
Extension(app): Extension<Arc<Web3ProxyApp>>, Extension(app): Extension<Arc<Web3ProxyApp>>,
Extension(cache): Extension<Arc<ResponseCache>>, Extension(cache): Extension<Arc<ResponseCache>>,
) -> impl IntoResponse { ) -> impl IntoResponse {
cache let (code, content_type, body) = cache
.get_or_insert_async::<Infallible, _>(&ResponseCacheKey::BackupsNeeded, async move { .get_or_insert_async::<Infallible, _>(&ResponseCacheKey::BackupsNeeded, async move {
Ok(_backups_needed(app).await) Ok(_backups_needed(app).await)
}) })
.await .await
.unwrap();
Response::builder()
.status(code)
.header("content-type", content_type)
.body(Full::from(body))
.unwrap()
} }
#[inline] #[inline]
async fn _backups_needed(app: Arc<Web3ProxyApp>) -> (StatusCode, Bytes) { async fn _backups_needed(app: Arc<Web3ProxyApp>) -> (StatusCode, &'static str, Bytes) {
let code = { let code = {
let consensus_rpcs = app let consensus_rpcs = app
.balanced_rpcs .balanced_rpcs
@ -75,9 +101,9 @@ async fn _backups_needed(app: Arc<Web3ProxyApp>) -> (StatusCode, Bytes) {
}; };
if matches!(code, StatusCode::OK) { if matches!(code, StatusCode::OK) {
(code, BACKUPS_NEEDED_FALSE.clone()) (code, CONTENT_TYPE_PLAIN, BACKUPS_NEEDED_FALSE.clone())
} else { } else {
(code, BACKUPS_NEEDED_TRUE.clone()) (code, CONTENT_TYPE_PLAIN, BACKUPS_NEEDED_TRUE.clone())
} }
} }
@ -89,16 +115,23 @@ pub async fn status(
Extension(app): Extension<Arc<Web3ProxyApp>>, Extension(app): Extension<Arc<Web3ProxyApp>>,
Extension(cache): Extension<Arc<ResponseCache>>, Extension(cache): Extension<Arc<ResponseCache>>,
) -> impl IntoResponse { ) -> impl IntoResponse {
cache let (code, content_type, body) = cache
.get_or_insert_async::<Infallible, _>(&ResponseCacheKey::Status, async move { .get_or_insert_async::<Infallible, _>(&ResponseCacheKey::Status, async move {
Ok(_status(app).await) Ok(_status(app).await)
}) })
.await .await
.unwrap();
Response::builder()
.status(code)
.header("content-type", content_type)
.body(Full::from(body))
.unwrap()
} }
// TODO: _status doesn't need to be async, but _quick_cache_ttl needs an async function // TODO: _status doesn't need to be async, but _quick_cache_ttl needs an async function
#[inline] #[inline]
async fn _status(app: Arc<Web3ProxyApp>) -> (StatusCode, Bytes) { async fn _status(app: Arc<Web3ProxyApp>) -> (StatusCode, &'static str, Bytes) {
// TODO: what else should we include? uptime, cache hit rates, cpu load, memory used // TODO: what else should we include? uptime, cache hit rates, cpu load, memory used
// TODO: the hostname is probably not going to change. only get once at the start? // TODO: the hostname is probably not going to change. only get once at the start?
let body = json!({ let body = json!({
@ -120,5 +153,5 @@ async fn _status(app: Arc<Web3ProxyApp>) -> (StatusCode, Bytes) {
StatusCode::INTERNAL_SERVER_ERROR StatusCode::INTERNAL_SERVER_ERROR
}; };
(code, body) (code, CONTENT_TYPE_JSON, body)
} }