autoconnect_web/
dockerflow.rs1use std::thread;
3
4use actix_web::{
5 web::{self, Data, Json},
6 HttpResponse, ResponseError,
7};
8use serde_json::json;
9
10use autoconnect_settings::AppState;
11use autopush_common::metric_name::MetricName;
12use autopush_common::metrics::StatsdClientExt;
13
14use crate::error::ApiError;
15
16pub fn config(config: &mut web::ServiceConfig) {
18 config
19 .service(web::resource("/status").route(web::get().to(status_route)))
20 .service(web::resource("/health").route(web::get().to(health_route)))
21 .service(web::resource("/v1/err/crit").route(web::get().to(log_check)))
22 .service(web::resource("/__error__").route(web::get().to(log_check)))
24 .service(web::resource("/__heartbeat__").route(web::get().to(health_route)))
26 .service(web::resource("/__lbheartbeat__").route(web::get().to(lb_heartbeat_route)))
27 .service(web::resource("/__version__").route(web::get().to(version_route)));
28}
29
30pub async fn health_route(state: Data<AppState>) -> Json<serde_json::Value> {
32 #[allow(unused_mut)]
33 let mut health = json!({
34 "status": if state
35 .db
36 .health_check()
37 .await
38 .map_err(|e| {
39 error!("Autoconnect Health Error: {:?}", e);
40 e
41 })
42 .is_ok() { "OK" } else {"ERROR"},
43 "version": env!("CARGO_PKG_VERSION"),
44 "connections": state.clients.count().await
45 });
46
47 #[cfg(feature = "reliable_report")]
48 {
49 health["reliability"] = json!(state.reliability.health_check().await.unwrap_or_else(|e| {
50 state
51 .metrics
52 .incr_with_tags(MetricName::ErrorRedisUnavailable)
53 .with_tag("application", "autoconnect")
54 .send();
55 error!("🔍🟥 Reliability reporting down: {:?}", e);
56 "ERROR"
57 }));
58 }
59
60 Json(health)
61}
62
63pub async fn status_route(state: Data<AppState>) -> Json<serde_json::Value> {
65 let mut status: std::collections::HashMap<&str, String> = std::collections::HashMap::new();
66 status.insert("version", env!("CARGO_PKG_VERSION").to_owned());
67 let check = state.db.health_check().await;
68 if check.is_ok() {
69 status.insert("status", "OK".to_owned());
70 } else {
71 status.insert("status", "ERROR".to_owned());
72 }
73 if let Some(err) = check.err().map(|v| v.to_string()) {
74 status.insert("error", err);
75 };
76
77 Json(json!(status))
78}
79
80pub async fn lb_heartbeat_route() -> HttpResponse {
82 HttpResponse::Ok().finish()
84}
85
86pub async fn version_route() -> HttpResponse {
88 HttpResponse::Ok()
91 .content_type("application/json")
92 .body(include_str!("../../../version.json"))
93}
94
95pub async fn log_check() -> Result<HttpResponse, ApiError> {
97 let err = ApiError::LogCheck;
98 error!(
99 "Test Critical Message";
100 "status_code" => err.status_code().as_u16(),
101 "errno" => err.errno(),
102 );
103
104 thread::spawn(|| {
105 panic!("LogCheck");
106 });
107
108 Err(err)
109}