Skip to content

Commit

Permalink
refactor health endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
Mr-Leshiy committed Apr 30, 2024
1 parent bf75d85 commit 87b3118
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 102 deletions.
40 changes: 8 additions & 32 deletions catalyst-gateway/bin/src/service/api/health/live_get.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
//! Implementation of the GET /health/live endpoint

use poem_extensions::{response, UniResponse::T204};
use tracing::{error, info, warn};

use crate::service::common::responses::{
resp_2xx::NoContent,
resp_4xx::ApiValidationError,
resp_5xx::{ServerError, ServiceUnavailable},
};
use poem_openapi::ApiResponse;

/// All responses
pub(crate) type AllResponses = response! {
204: NoContent,
400: ApiValidationError,
500: ServerError,
503: ServiceUnavailable,
};
#[derive(ApiResponse)]
pub(crate) enum AllResponses {
/// Service is Started and can serve requests.
#[oai(status = 204)]
NoContent,
}

/// # GET /health/live
///
Expand All @@ -26,24 +19,7 @@ pub(crate) type AllResponses = response! {
///
/// In this service, liveness is assumed unless there are multiple panics generated
/// by an endpoint in a short window.
///
/// ## Responses
///
/// * 204 No Content - Service is OK and can keep running.
/// * 400 API Validation Error
/// * 500 Server Error - If anything within this function fails unexpectedly. (Possible
/// but unlikely)
/// * 503 Service Unavailable - Service is possibly not running reliably.
#[allow(clippy::unused_async)]
pub(crate) async fn endpoint() -> AllResponses {
// TODO: Detect if too many panics have occurred in a defined window.
// If so, return a 503
// T503(ServiceUnavailable)

info!("liveness check");
warn!("liveness check - warn");
error!("liveness check - error");

// otherwise everything seems to be A-OK
T204(NoContent)
AllResponses::NoContent
}
21 changes: 0 additions & 21 deletions catalyst-gateway/bin/src/service/api/health/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,6 @@ impl HealthApi {
///
/// *This endpoint is for internal use of the service deployment infrastructure.
/// It may not be exposed publicly.*
///
/// ## Responses
///
/// * 204 No Content - Service is Started and can serve requests.
/// * 500 Server Error - If anything within this function fails unexpectedly.
/// * 503 Service Unavailable - Service has not started, do not send other requests
/// yet.
async fn started_get(&self) -> started_get::AllResponses {
started_get::endpoint().await
}
Expand All @@ -46,13 +39,6 @@ impl HealthApi {
///
/// *This endpoint is for internal use of the service deployment infrastructure.
/// It may not be exposed publicly.*
///
/// ## Responses
///
/// * 204 No Content - Service is Ready and can serve requests.
/// * 500 Server Error - If anything within this function fails unexpectedly.
/// * 503 Service Unavailable - Service is not ready, requests to other
/// endpoints should not be sent until the service becomes ready.
async fn ready_get(&self, state: Data<&Arc<State>>) -> ready_get::AllResponses {
ready_get::endpoint(state).await
}
Expand All @@ -66,13 +52,6 @@ impl HealthApi {
///
/// *This endpoint is for internal use of the service deployment infrastructure.
/// It may not be exposed publicly. Refer to []*
///
/// ## Responses
///
/// * 204 No Content - Service is OK and can keep running.
/// * 500 Server Error - If anything within this function fails unexpectedly.
/// (Possible but unlikely)
/// * 503 Service Unavailable - Service is possibly not running reliably.
async fn live_get(&self) -> live_get::AllResponses {
live_get::endpoint().await
}
Expand Down
43 changes: 18 additions & 25 deletions catalyst-gateway/bin/src/service/api/health/ready_get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,29 @@
use std::sync::Arc;

use poem::web::Data;
use poem_extensions::{
response,
UniResponse::{T204, T503},
};
use poem_openapi::{payload::Json, ApiResponse};

use crate::{
event_db::schema_check::MismatchedSchemaError,
service::common::responses::{
resp_2xx::NoContent,
resp_4xx::ApiValidationError,
resp_5xx::{handle_5xx_response, ServerError, ServiceUnavailable},
},
service::common::{objects::server_error::ServerError, responses::handle_5xx_response},
state::State,
};

/// All responses
pub(crate) type AllResponses = response! {
204: NoContent,
400: ApiValidationError,
500: ServerError,
503: ServiceUnavailable,
};
#[derive(ApiResponse)]
pub(crate) enum AllResponses {
/// Service is Started and can serve requests.
#[oai(status = 204)]
NoContent,
/// Internal Server Error.
///
/// *The contents of this response should be reported to the projects issue tracker.*
#[oai(status = 500)]
ServerError(Json<ServerError>),
/// Service is not ready, do not send other requests.
#[oai(status = 503)]
ServiceUnavailable,
}

/// # GET /health/ready
///
Expand All @@ -43,23 +44,15 @@ pub(crate) type AllResponses = response! {
/// and is not able to properly service requests while it is occurring.
/// This would let the load balancer shift traffic to other instances of this
/// service that are ready.
///
/// ## Responses
///
/// * 204 No Content - Service is Ready to serve requests.
/// * 400 API Validation Error
/// * 500 Server Error - If anything within this function fails unexpectedly. (Possible
/// but unlikely)
/// * 503 Service Unavailable - Service is not ready, do not send other requests.
pub(crate) async fn endpoint(state: Data<&Arc<State>>) -> AllResponses {
match state.event_db().schema_version_check().await {
Ok(_) => {
tracing::debug!("DB schema version status ok");
T204(NoContent)
AllResponses::NoContent
},
Err(err) if err.is::<MismatchedSchemaError>() => {
tracing::error!("{err}");
T503(ServiceUnavailable)
AllResponses::ServiceUnavailable
},
Err(err) => handle_5xx_response!(err),
}
Expand Down
31 changes: 8 additions & 23 deletions catalyst-gateway/bin/src/service/api/health/started_get.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
//! Implementation of the GET /health/started endpoint

use poem_extensions::{response, UniResponse::T204};

use crate::service::common::responses::{
resp_2xx::NoContent,
resp_4xx::ApiValidationError,
resp_5xx::{ServerError, ServiceUnavailable},
};
use poem_openapi::ApiResponse;

/// All responses
pub(crate) type AllResponses = response! {
204: NoContent,
400: ApiValidationError,
500: ServerError,
503: ServiceUnavailable,
};
#[derive(ApiResponse)]
pub(crate) enum AllResponses {
/// Service is Started and can serve requests.
#[oai(status = 204)]
NoContent,
}

/// # GET /health/started
///
Expand All @@ -33,16 +27,7 @@ pub(crate) type AllResponses = response! {
/// into memory or processed in some way before the API can return valid
/// responses. In that scenario this endpoint would return 503 until that
/// startup processing was fully completed.
///
/// ## Responses
///
/// * 204 No Content - Service is Started and can serve requests.
/// * 400 API Validation Error
/// * 500 Server Error - If anything within this function fails unexpectedly. (Possible
/// but unlikely)
/// * 503 Service Unavailable - Service has not started, do not send other requests.
#[allow(clippy::unused_async)]
pub(crate) async fn endpoint() -> AllResponses {
// otherwise everything seems to be A-OK
T204(NoContent)
AllResponses::NoContent
}
1 change: 1 addition & 0 deletions catalyst-gateway/bin/src/service/common/objects/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
pub(crate) mod cardano;
pub(crate) mod error_message;
pub(crate) mod legacy;
pub(crate) mod server_error;
52 changes: 52 additions & 0 deletions catalyst-gateway/bin/src/service/common/objects/server_error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//! Define `ServerError` type.

use poem_openapi::{types::Example, Object};
use url::Url;
use uuid::Uuid;

/// While using macro-vis lib, you will get the `uncommon_codepoints` warning, so you will
/// probably want to place this in your crate root
use crate::settings::generate_github_issue_url;

#[derive(Debug, Object)]
#[oai(example, skip_serializing_if_is_none)]
/// Server Error response to a Bad request.
pub(crate) struct ServerError {
/// Unique ID of this Server Error so that it can be located easily for debugging.
id: Uuid,
/// *Optional* SHORT Error message.
/// Will not contain sensitive information, internal details or backtraces.
// TODO(bkioshn): https://github.com/input-output-hk/catalyst-voices/issues/239
#[oai(validator(max_length = "100", pattern = "^[0-9a-zA-Z].*$"))]
msg: String,
/// A URL to report an issue.
// TODO(bkioshn): https://github.com/input-output-hk/catalyst-voices/issues/239
#[oai(validator(max_length = "1000"))]
issue: Option<Url>,
}

impl ServerError {
/// Create a new Server Error Response Payload.
pub(crate) fn new(msg: Option<String>) -> Self {
let msg = msg.unwrap_or(
"Internal Server Error. Please report the issue to the service owner.".to_string(),
);
let id = Uuid::new_v4();
let issue_title = format!("Internal Server Error - {id}");
let issue = generate_github_issue_url(&issue_title);

Self { id, msg, issue }
}

/// Get the id of this Server Error.
pub(crate) fn id(&self) -> Uuid {
self.id
}
}

impl Example for ServerError {
/// Example for the Server Error Payload.
fn example() -> Self {
Self::new(Some("Server Error".to_string()))
}
}
19 changes: 18 additions & 1 deletion catalyst-gateway/bin/src/service/common/responses/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
//! Generic Responses are all contained in their own modules, grouped by response codes.
#[macro_use]

pub(crate) mod resp_2xx;
pub(crate) mod resp_4xx;
pub(crate) mod resp_5xx;

/// Handle a 5xx response.
/// Returns a Server Error or a Service Unavailable response.
/// Logging error message.
/// Argument must be `anyhow::Error` type.
macro_rules! handle_5xx_response {
($err:ident) => {{
if $err.is::<bb8::RunError<tokio_postgres::Error>>() {
AllResponses::ServiceUnavailable
} else {
let error = crate::service::common::objects::server_error::ServerError::new(None);
let id = error.id();
tracing::error!(id = format!("{id}"), "{}", $err);
AllResponses::ServerError(Json(error))
}
}};
}
pub(crate) use handle_5xx_response;

0 comments on commit 87b3118

Please sign in to comment.