Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(health): extract health into separate crate #1008

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"blockscout-auth",
"blockscout-client/crate",
"blockscout-db",
"endpoints/health",
"blockscout-service-launcher",
"display-bytes",
"env-collector",
Expand Down
14 changes: 14 additions & 0 deletions libs/endpoints/health/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "blockscout-endpoint-health"
version = "0.1.0"
description = "Configuration tools for compiling health endpoint"
license = "MIT"
repository = "https://github.com/blockscout/blockscout-rs"
keywords = ["blockscout", "service", "http", "microservices", "health", "endpoint"]
categories = ["web-programming::http-server"]
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
prost-build = "0.11"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it is better to leave the proto/health/v1/health.proto file as it is used by some of other services

File renamed without changes.
49 changes: 49 additions & 0 deletions libs/endpoints/health/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//! Tools for setting up `/health` endpoint.
//!
//! ## Usage
//! (example can be seen in `stats-proto` crate in this repo)
//!
//! 1. In `build.rs` in your crateuse [`add_to_compile_config`],
//! [`proto_files`], and [`includes`] for compiling `health.proto`
//! to rust code using [`prost_build`].
//!
//! 2. To include the generated code in your project, add the following to `lib.rs`
//! (`/grpc.health.v1.rs` is the file name chosen based on `package` in `.proto` file):
//! ```ignore
//! pub mod grpc {
//! pub mod health {
//! pub mod v1 {
//! include!(concat!(env!("OUT_DIR"), "/grpc.health.v1.rs"));
//! }
//! }
//! }
//! ```
//!
//! 3. To enable swagger generation, add the following in `api_config_http.yaml`'s
//! http rules:
//! ```custom,{class=language-yaml}
//! - selector: grpc.health.v1.Health.Check
//! get: /health
//! ```
//!
//! Now the types should be available in `grpc::health::v1` module, and swagger
//! entry for the endpoint should appear

use std::path::{Path, PathBuf};

use prost_build::Config;

pub fn add_to_compile_config(config: &mut Config) {
config.bytes([".grpc.health"]).type_attribute(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion it is the client code responsibility to decide should the generated code use bytes or not, so I suggest to remove it from here and only leave .bytes(["."]) in the client code

".grpc.health",
"#[actix_prost_macros::serde(rename_all=\"snake_case\")]",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, wdyt about leaving the case definition as the client responsibility as well?

);
}

pub fn proto_files(path_to_swagger_crate: &Path) -> Vec<PathBuf> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub fn proto_files(path_to_swagger_crate: &Path) -> Vec<PathBuf> {
pub fn proto_files(path_to_health_crate: &Path) -> Vec<PathBuf> {

vec![path_to_swagger_crate.join("proto/health.proto")]
}

pub fn includes(path_to_swagger_crate: &Path) -> Vec<PathBuf> {
vec![path_to_swagger_crate.join("proto")]
}
8 changes: 8 additions & 0 deletions stats/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions stats/stats-proto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ serde_json = "1.0"
actix-prost-build = { git = "https://github.com/blockscout/actix-prost" }
tonic-build = "0.8"
prost-build = "0.11"
blockscout-endpoint-health = { path = "../../libs/endpoints/health" }
38 changes: 30 additions & 8 deletions stats/stats-proto/build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use actix_prost_build::{ActixGenerator, GeneratorList};
use prost_build::{Config, ServiceGenerator};
use std::path::Path;
use std::path::{Path, PathBuf};

// custom function to include custom generator
fn compile(
Expand All @@ -16,33 +16,55 @@ fn compile(
.protoc_arg("--openapiv2_opt")
.protoc_arg("grpc_api_configuration=proto/api_config_http.yaml,output_format=yaml,allow_merge=true,merge_file_name=stats,json_names_for_fields=false")
.bytes(["."])
.type_attribute(".", "#[actix_prost_macros::serde(rename_all=\"snake_case\")]")
.type_attribute(".blockscout.stats", "#[actix_prost_macros::serde(rename_all=\"snake_case\")]")
.field_attribute(
".blockscout.stats.v1.HealthCheckRequest.service",
"#[serde(default)]"
)
Comment on lines 20 to 23
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets move that definition into the health endpoint crate

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe just add optional to service field?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to add to proto then remove

.field_attribute(".blockscout.stats.v1.Point.is_approximate", "#[serde(skip_serializing_if = \"std::ops::Not::not\")]")
.field_attribute(".blockscout.stats.v1.Point.is_approximate", "#[serde(default)]")
.field_attribute(".blockscout.stats.v1.GetLineChartRequest.resolution", "#[serde(default)]");
blockscout_endpoint_health::add_to_compile_config(&mut config);

config.compile_protos(protos, includes)?;
Ok(())
}

fn vec_path_buf_to_string(v: Vec<PathBuf>) -> Vec<String> {
v.into_iter()
.map(|path| {
path.to_str()
.expect("Non UTF-8 paths are not supported")
.to_string()
})
.collect()
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
let swagger_crate_folder = Path::new("../../libs/endpoints/health");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

swagger or health ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, will this work in other than blockscou-rs repositories and will this build inside docker containers?


// We need to rebuild proto lib only if any of proto definitions
// (or corresponding http mapping) has been changed.
println!("cargo:rerun-if-changed=proto/");
let mut proto_files_folders = ["proto/"].map(PathBuf::from).to_vec();
proto_files_folders.extend(blockscout_endpoint_health::includes(swagger_crate_folder));
let proto_files_folders = vec_path_buf_to_string(proto_files_folders);

for folder in &proto_files_folders {
println!("cargo:rerun-if-changed={folder}/");
}

let mut protos = ["proto/stats.proto"].map(PathBuf::from).to_vec();
protos.extend(blockscout_endpoint_health::proto_files(
swagger_crate_folder,
));
let protos = vec_path_buf_to_string(protos);
sevenzing marked this conversation as resolved.
Show resolved Hide resolved

std::fs::create_dir_all("./swagger").unwrap();
let gens = Box::new(GeneratorList::new(vec![
tonic_build::configure().service_generator(),
Box::new(ActixGenerator::new("proto/api_config_http.yaml").unwrap()),
]));
compile(
&["proto/stats.proto", "proto/health.proto"],
&["proto"],
gens,
)?;

compile(&protos, &proto_files_folders, gens)?;
Ok(())
}
2 changes: 1 addition & 1 deletion stats/stats-proto/proto/api_config_http.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ http:
- selector: blockscout.stats.v1.StatsService.GetLineChart
get: /api/v1/lines/{name}

- selector: blockscout.stats.v1.Health.Check
- selector: grpc.health.v1.Health.Check
get: /health
62 changes: 0 additions & 62 deletions stats/stats-proto/proto/health.proto

This file was deleted.

8 changes: 8 additions & 0 deletions stats/stats-proto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,13 @@ pub mod blockscout {
}
}

pub mod grpc {
pub mod health {
pub mod v1 {
include!(concat!(env!("OUT_DIR"), "/grpc.health.v1.rs"));
}
}
}

#[cfg(test)]
mod tests;
11 changes: 9 additions & 2 deletions stats/stats-proto/swagger/stats.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,15 @@ paths:
/health:
get:
summary: |-
If the requested service is unknown, the call will fail with status
NOT_FOUND.
Check gets the health of the specified service. If the requested service
is unknown, the call will fail with status NOT_FOUND. If the caller does
not specify a service name, the server should respond with its overall
health status.
description: |-
Clients should set a deadline when calling Check, and can declare the
server unhealthy if they do not receive a timely response.

Check implementations should be idempotent and side effect free.
operationId: Health_Check
responses:
"200":
Expand Down
2 changes: 1 addition & 1 deletion stats/stats-server/src/health.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use stats_proto::blockscout::stats::v1::{
use stats_proto::grpc::health::v1::{
health_check_response, health_server::Health, HealthCheckRequest, HealthCheckResponse,
};

Expand Down
11 changes: 6 additions & 5 deletions stats/stats-server/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ use crate::{

use blockscout_service_launcher::launcher::{self, LaunchSettings};
use sea_orm::{ConnectOptions, Database};
use stats_proto::blockscout::stats::v1::{
health_actix::route_health,
health_server::HealthServer,
stats_service_actix::route_stats_service,
stats_service_server::{StatsService, StatsServiceServer},
use stats_proto::{
blockscout::stats::v1::{
stats_service_actix::route_stats_service,
stats_service_server::{StatsService, StatsServiceServer},
},
grpc::health::v1::{health_actix::route_health, health_server::HealthServer},
};

const SERVICE_NAME: &str = "stats";
Expand Down
Loading