-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge #512: Implement a health check for the tracker container
5e0a686 refactor: [#508] extract health check methods (Jose Celano) bf23479 feat: [#508] add health check for UDP tracker (Jose Celano) 2a05590 refactor: [#508] move UDP tracker client to production code (Jose Celano) 7421306 feat: [#508] add health check enpoint to HTTP tracker (Jose Celano) ef296f7 feat: [#508] app health check endpoint checks API (Jose Celano) e1a45a2 feat: [#508] Health Check API but no checks yet (Jose Celano) 48ac64f feat: [#508] add container healthcheck for API (Jose Celano) 0ef4e34 feat: [#508] add new binary HTTP health check (Jose Celano) f1c7ccc feat: add cargo dependency reqwest (Jose Celano) Pull request description: We need to check the three services provided by the container: - [x] API - [x] HTTP Tracker (1 or more) - [x] UDP Tracker (1 or more) And we also need to: - [x] Check them only when they are enabled in the configuration. ### Implementation - [x] High-level health-checker API (in the future management API). It only checks enabled services. It makes a request to the service healthcheck endpoints. - [x] Healthcheck API endpoint - [x] Healthcheck HTTP Tracker endpoint - [x] Healthcheck UDP Tracker request (using the `connect` request endpoint). With the default configuration, you can use the endpoint: http://localhost:1313/health_check It will return an OK Json response: ```json { "status": "Ok", "message": "" } ``` or an Error response: ```json { "status": "Error", "message": "API is not healthy. Health check endpoint: http://127.0.0.1:1212/health_check" } ``` **NOTICE**: health checks are not executed when services use port 0 in the configuration. Service launchers must be changed to return the bound port so the health checker handler can connect. ACKs for top commit: josecelano: ACK 5e0a686 Tree-SHA512: d5e3dc788a10654c7b7b11388c4b559aecc899fafeaffc4dce30c9309c1c42feeb671f66db8aa1f474dc3b27dff9dbd5df4e02b2634e433cffb4772bedd2e115
- Loading branch information
Showing
44 changed files
with
687 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
//! Minimal `curl` or `wget` to be used for container health checks. | ||
//! | ||
//! It's convenient to avoid using third-party libraries because: | ||
//! | ||
//! - They are harder to maintain. | ||
//! - They introduce new attack vectors. | ||
use std::{env, process}; | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
let args: Vec<String> = env::args().collect(); | ||
if args.len() != 2 { | ||
eprintln!("Usage: cargo run --bin http_health_check <HEALTH_URL>"); | ||
eprintln!("Example: cargo run --bin http_health_check http://127.0.0.1:1212/health_check"); | ||
std::process::exit(1); | ||
} | ||
|
||
println!("Health check ..."); | ||
|
||
let url = &args[1].clone(); | ||
|
||
match reqwest::get(url).await { | ||
Ok(response) => { | ||
if response.status().is_success() { | ||
println!("STATUS: {}", response.status()); | ||
process::exit(0); | ||
} else { | ||
println!("Non-success status received."); | ||
process::exit(1); | ||
} | ||
} | ||
Err(err) => { | ||
println!("ERROR: {err}"); | ||
process::exit(1); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
//! Health Check API job starter. | ||
//! | ||
//! The [`health_check_api::start_job`](crate::bootstrap::jobs::health_check_api::start_job) | ||
//! function starts the Health Check REST API. | ||
//! | ||
//! The [`health_check_api::start_job`](crate::bootstrap::jobs::health_check_api::start_job) | ||
//! function spawns a new asynchronous task, that tasks is the "**launcher**". | ||
//! The "**launcher**" starts the actual server and sends a message back | ||
//! to the main application. The main application waits until receives | ||
//! the message [`ApiServerJobStarted`] | ||
//! from the "**launcher**". | ||
//! | ||
//! The "**launcher**" is an intermediary thread that decouples the Health Check | ||
//! API server from the process that handles it. | ||
//! | ||
//! Refer to the [configuration documentation](https://docs.rs/torrust-tracker-configuration) | ||
//! for the API configuration options. | ||
use std::net::SocketAddr; | ||
use std::sync::Arc; | ||
|
||
use log::info; | ||
use tokio::sync::oneshot; | ||
use tokio::task::JoinHandle; | ||
use torrust_tracker_configuration::Configuration; | ||
|
||
use crate::servers::health_check_api::server; | ||
|
||
/// This is the message that the "launcher" spawned task sends to the main | ||
/// application process to notify the API server was successfully started. | ||
/// | ||
/// > **NOTICE**: it does not mean the API server is ready to receive requests. | ||
/// It only means the new server started. It might take some time to the server | ||
/// to be ready to accept request. | ||
#[derive(Debug)] | ||
pub struct ApiServerJobStarted { | ||
pub bound_addr: SocketAddr, | ||
} | ||
|
||
/// This function starts a new Health Check API server with the provided | ||
/// configuration. | ||
/// | ||
/// The functions starts a new concurrent task that will run the API server. | ||
/// This task will send a message to the main application process to notify | ||
/// that the API server was successfully started. | ||
/// | ||
/// # Panics | ||
/// | ||
/// It would panic if unable to send the `ApiServerJobStarted` notice. | ||
pub async fn start_job(config: Arc<Configuration>) -> JoinHandle<()> { | ||
let bind_addr = config | ||
.health_check_api | ||
.bind_address | ||
.parse::<std::net::SocketAddr>() | ||
.expect("Health Check API bind_address invalid."); | ||
|
||
let (tx, rx) = oneshot::channel::<ApiServerJobStarted>(); | ||
|
||
// Run the API server | ||
let join_handle = tokio::spawn(async move { | ||
info!("Starting Health Check API server: http://{}", bind_addr); | ||
|
||
let handle = server::start(bind_addr, tx, config.clone()); | ||
|
||
if let Ok(()) = handle.await { | ||
info!("Health Check API server on http://{} stopped", bind_addr); | ||
} | ||
}); | ||
|
||
// Wait until the API server job is running | ||
match rx.await { | ||
Ok(_msg) => info!("Torrust Health Check API server started"), | ||
Err(e) => panic!("the Health Check API server was dropped: {e}"), | ||
} | ||
|
||
join_handle | ||
} |
Oops, something went wrong.