From 7b57c1b7299fbc100a68a3f72921bce2bb17e8ab Mon Sep 17 00:00:00 2001 From: Richard Bertok Date: Thu, 22 Aug 2024 13:31:56 +0200 Subject: [PATCH] feat(http-server): add health check and version endpoints (#33) Description --- We need to have a health check and version endpoint for easier deployments. New endpoints: - `http://127.0.0.1:19000/health` - `http://127.0.0.1:19000/version` Motivation and Context --- How Has This Been Tested? --- What process can a PR reviewer use to test or verify this change? --- Breaking Changes --- - [x] None - [ ] Requires data directory on base node to be deleted - [ ] Requires hard fork - [ ] Other - Please specify --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 5 +++-- src/cli/args.rs | 8 ++++---- src/cli/commands/list_tribes.rs | 2 +- src/cli/commands/util.rs | 2 +- src/server/config.rs | 13 ++++++------- src/server/grpc/util.rs | 20 +++++++++----------- src/server/http/health.rs | 8 ++++++++ src/server/http/mod.rs | 3 +++ src/server/http/{stats => }/server.rs | 7 +++++-- src/server/http/stats/handlers.rs | 2 +- src/server/http/stats/mod.rs | 1 - src/server/http/version.rs | 10 ++++++++++ src/server/server.rs | 10 +++++----- 15 files changed, 58 insertions(+), 37 deletions(-) create mode 100644 src/server/http/health.rs rename src/server/http/{stats => }/server.rs (92%) create mode 100644 src/server/http/version.rs diff --git a/Cargo.lock b/Cargo.lock index f856b39..6487860 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4278,7 +4278,7 @@ dependencies = [ [[package]] name = "sha_p2pool" -version = "0.1.3" +version = "0.1.4-pre.0" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 0604149..f7315eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sha_p2pool" -version = "0.1.3" +version = "0.1.4-pre.0" edition = "2021" [dependencies] diff --git a/README.md b/README.md index 9fabc1c..b116996 100644 --- a/README.md +++ b/README.md @@ -38,9 +38,10 @@ How to use Please note that `18145` is the port where `base node's gRPC` is running, so if it is different from the default one (`18145`) just use the right port. -- Start sha p2pool by running the binary simple `$ ./sha_p2pool` or using `Cargo` (if installed and want to build from +- Start sha p2pool by running the binary simple `$ ./sha_p2pool start` or using `Cargo` (if installed and want to build + from source): - `$ cargo build --release && ./target/release/sha_p2pool` + `$ cargo build --release && ./target/release/sha_p2pool start` **Note:** For more information about usage of p2pool, just run `$ sha_p2pool --help`! diff --git a/src/cli/args.rs b/src/cli/args.rs index 735478c..d295fd8 100644 --- a/src/cli/args.rs +++ b/src/cli/args.rs @@ -87,11 +87,11 @@ pub struct StartArgs { #[arg(long, value_name = "mdns-disabled", default_value_t = false)] pub mdns_disabled: bool, - /// Stats server disabled + /// HTTP server disabled /// - /// If set, local stats HTTP server is disabled. - #[arg(long, value_name = "stats-server-disabled", default_value_t = false)] - pub stats_server_disabled: bool, + /// If set, local HTTP server (stats, health-check, status etc...) is disabled. + #[arg(long, value_name = "http-server-disabled", default_value_t = false)] + pub http_server_disabled: bool, } #[derive(Subcommand, Clone, Debug)] diff --git a/src/cli/commands/list_tribes.rs b/src/cli/commands/list_tribes.rs index f68bdda..de97ce4 100644 --- a/src/cli/commands/list_tribes.rs +++ b/src/cli/commands/list_tribes.rs @@ -24,7 +24,7 @@ pub async fn handle_list_tribes( let cli_ref = cli.clone(); let mut args_clone = args.clone(); args_clone.mining_disabled = true; - args_clone.stats_server_disabled = true; + args_clone.http_server_disabled = true; let mut shutdown = Shutdown::new(); let shutdown_signal = shutdown.to_signal(); let (peer_store_channel_tx, peer_store_channel_rx) = oneshot::channel::>(); diff --git a/src/cli/commands/util.rs b/src/cli/commands/util.rs index 1479c8a..9695b69 100644 --- a/src/cli/commands/util.rs +++ b/src/cli/commands/util.rs @@ -67,7 +67,7 @@ pub async fn server( config_builder.with_mining_enabled(!args.mining_disabled); config_builder.with_mdns_enabled(!args.mdns_disabled); - config_builder.with_stats_server_enabled(!args.stats_server_disabled); + config_builder.with_http_server_enabled(!args.http_server_disabled); if let Some(stats_server_port) = args.stats_server_port { config_builder.with_stats_server_port(stats_server_port); } diff --git a/src/server/config.rs b/src/server/config.rs index 06de96e..7350534 100644 --- a/src/server/config.rs +++ b/src/server/config.rs @@ -5,9 +5,8 @@ use std::{path::PathBuf, time::Duration}; use libp2p::identity::Keypair; -use crate::server::http::stats; use crate::server::p2p::Tribe; -use crate::server::{p2p, p2p::peer_store::PeerStoreConfig}; +use crate::server::{http, p2p, p2p::peer_store::PeerStoreConfig}; /// Config is the server configuration struct. #[derive(Clone)] @@ -19,7 +18,7 @@ pub struct Config { pub peer_store: PeerStoreConfig, pub p2p_service: p2p::Config, pub mining_enabled: bool, - pub stats_server: stats::server::Config, + pub http_server: http::server::Config, } impl Default for Config { @@ -32,7 +31,7 @@ impl Default for Config { peer_store: PeerStoreConfig::default(), p2p_service: p2p::Config::default(), mining_enabled: true, - stats_server: stats::server::Config::default(), + http_server: http::server::Config::default(), } } } @@ -111,13 +110,13 @@ impl ConfigBuilder { self } - pub fn with_stats_server_enabled(&mut self, config: bool) -> &mut Self { - self.config.stats_server.enabled = config; + pub fn with_http_server_enabled(&mut self, config: bool) -> &mut Self { + self.config.http_server.enabled = config; self } pub fn with_stats_server_port(&mut self, config: u16) -> &mut Self { - self.config.stats_server.port = config; + self.config.http_server.port = config; self } diff --git a/src/server/grpc/util.rs b/src/server/grpc/util.rs index 8b04916..f69d8f4 100644 --- a/src/server/grpc/util.rs +++ b/src/server/grpc/util.rs @@ -8,7 +8,6 @@ use minotari_app_grpc::tari_rpc::base_node_client::BaseNodeClient; use minotari_node_grpc_client::BaseNodeGrpcClient; use tari_shutdown::ShutdownSignal; use tokio::select; -use tokio::time::sleep; use tonic::transport::Channel; use crate::server::grpc::error::{Error, TonicError}; @@ -26,22 +25,21 @@ pub async fn connect_base_node( Err(error) => { error!("[Retry] Failed to connect to Tari base node: {:?}", error.to_string()); let mut client = None; + let mut retry_interval = tokio::time::interval(Duration::from_secs(5)); tokio::pin!(shutdown_signal); while client.is_none() { - sleep(Duration::from_secs(5)).await; - match BaseNodeGrpcClient::connect(base_node_address.clone()) - .await - .map_err(|e| Error::Tonic(TonicError::Transport(e))) - { - Ok(curr_client) => client = Some(curr_client), - Err(error) => error!("[Retry] Failed to connect to Tari base node: {:?}", error.to_string()), - } select! { () = &mut shutdown_signal => { return Err(Error::Shutdown); } - else => { - continue; + _ = retry_interval.tick() => { + match BaseNodeGrpcClient::connect(base_node_address.clone()) + .await + .map_err(|e| Error::Tonic(TonicError::Transport(e))) + { + Ok(curr_client) => client = Some(curr_client), + Err(error) => error!("[Retry] Failed to connect to Tari base node: {:?}", error.to_string()), + } } } } diff --git a/src/server/http/health.rs b/src/server/http/health.rs new file mode 100644 index 0000000..4c6aed0 --- /dev/null +++ b/src/server/http/health.rs @@ -0,0 +1,8 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use axum::http::StatusCode; + +pub async fn handle_health() -> Result { + Ok(StatusCode::OK) +} diff --git a/src/server/http/mod.rs b/src/server/http/mod.rs index 6785168..f987327 100644 --- a/src/server/http/mod.rs +++ b/src/server/http/mod.rs @@ -1,4 +1,7 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause +mod health; +pub mod server; pub mod stats; +mod version; diff --git a/src/server/http/stats/server.rs b/src/server/http/server.rs similarity index 92% rename from src/server/http/stats/server.rs rename to src/server/http/server.rs index a721c23..ceddd48 100644 --- a/src/server/http/stats/server.rs +++ b/src/server/http/server.rs @@ -11,6 +11,7 @@ use thiserror::Error; use tokio::io; use crate::server::http::stats::handlers; +use crate::server::http::{health, version}; use crate::server::p2p::peer_store::PeerStore; use crate::server::p2p::Tribe; use crate::server::stats_store::StatsStore; @@ -39,7 +40,7 @@ pub enum Error { IO(#[from] io::Error), } -pub struct StatsServer +pub struct HttpServer where S: ShareChain, { @@ -59,7 +60,7 @@ pub struct AppState { pub tribe: Tribe, } -impl StatsServer +impl HttpServer where S: ShareChain, { @@ -85,6 +86,8 @@ where pub fn routes(&self) -> Router { Router::new() .route("/stats", get(handlers::handle_get_stats)) + .route("/health", get(health::handle_health)) + .route("/version", get(version::handle_version)) .with_state(AppState { share_chain: self.share_chain.clone(), peer_store: self.peer_store.clone(), diff --git a/src/server/http/stats/handlers.rs b/src/server/http/stats/handlers.rs index 5c6a487..604bd7f 100644 --- a/src/server/http/stats/handlers.rs +++ b/src/server/http/stats/handlers.rs @@ -14,8 +14,8 @@ use tari_core::consensus::ConsensusManager; use tari_core::transactions::tari_amount::MicroMinotari; use tari_utilities::epoch_time::EpochTime; +use crate::server::http::server::AppState; use crate::server::http::stats::models::{BlockStats, EstimatedEarnings, Stats, TribeDetails}; -use crate::server::http::stats::server::AppState; use crate::server::http::stats::{ MINER_STAT_ACCEPTED_BLOCKS_COUNT, MINER_STAT_REJECTED_BLOCKS_COUNT, P2POOL_STAT_ACCEPTED_BLOCKS_COUNT, P2POOL_STAT_REJECTED_BLOCKS_COUNT, diff --git a/src/server/http/stats/mod.rs b/src/server/http/stats/mod.rs index 72c4074..e8a7e6b 100644 --- a/src/server/http/stats/mod.rs +++ b/src/server/http/stats/mod.rs @@ -8,4 +8,3 @@ pub const P2POOL_STAT_REJECTED_BLOCKS_COUNT: &str = "p2pool_rejected_blocks_coun pub mod handlers; pub mod models; -pub mod server; diff --git a/src/server/http/version.rs b/src/server/http/version.rs new file mode 100644 index 0000000..baafea6 --- /dev/null +++ b/src/server/http/version.rs @@ -0,0 +1,10 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use axum::http::StatusCode; + +const VERSION: &str = env!("CARGO_PKG_VERSION"); + +pub async fn handle_version() -> Result { + Ok(VERSION.to_string()) +} diff --git a/src/server/server.rs b/src/server/server.rs index 92a7d24..87b9eb8 100644 --- a/src/server/server.rs +++ b/src/server/server.rs @@ -13,7 +13,7 @@ use minotari_app_grpc::tari_rpc::{base_node_server::BaseNodeServer, sha_p2_pool_ use tari_shutdown::ShutdownSignal; use thiserror::Error; -use crate::server::http::stats::server::StatsServer; +use crate::server::http::server::HttpServer; use crate::server::p2p::peer_store::PeerStore; use crate::server::stats_store::StatsStore; use crate::{ @@ -46,7 +46,7 @@ where p2p_service: p2p::Service, base_node_grpc_service: Option>, p2pool_grpc_service: Option>>, - stats_server: Option>>, + stats_server: Option>>, shutdown_signal: ShutdownSignal, } @@ -93,12 +93,12 @@ where p2pool_server = Some(ShaP2PoolServer::new(p2pool_grpc_service)); } - let stats_server = if config.stats_server.enabled { - Some(Arc::new(StatsServer::new( + let stats_server = if config.http_server.enabled { + Some(Arc::new(HttpServer::new( share_chain.clone(), tribe_peer_store.clone(), stats_store.clone(), - config.stats_server.port, + config.http_server.port, config.p2p_service.tribe.clone(), shutdown_signal.clone(), )))