update health to be more helpful
This commit is contained in:
parent
89d115b61d
commit
004def8fbb
7 changed files with 135 additions and 15 deletions
27
Cargo.lock
generated
27
Cargo.lock
generated
|
@ -48,6 +48,7 @@ dependencies = [
|
|||
"async-graphql",
|
||||
"async-graphql-axum",
|
||||
"axum",
|
||||
"chrono",
|
||||
"lazy_static",
|
||||
"reqwest",
|
||||
"serde",
|
||||
|
@ -76,6 +77,7 @@ dependencies = [
|
|||
"async-trait",
|
||||
"base64",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"fast_chemail",
|
||||
"fnv",
|
||||
"futures-util",
|
||||
|
@ -329,8 +331,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
|
@ -744,7 +749,7 @@ checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1141,7 +1146,7 @@ checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
||||
|
@ -1843,6 +1848,7 @@ dependencies = [
|
|||
"bitflags",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"crc",
|
||||
"crossbeam-queue",
|
||||
"dirs",
|
||||
|
@ -2038,6 +2044,17 @@ dependencies = [
|
|||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
|
@ -2419,6 +2436,12 @@ dependencies = [
|
|||
"try-lock",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
|
|
@ -8,11 +8,12 @@ edition = "2021"
|
|||
[dependencies]
|
||||
serde_json = "1.0.89"
|
||||
serde = "1.0.149"
|
||||
async-graphql = { version = "5.0.3" }
|
||||
async-graphql = { version = "5.0.3", features = ["chrono"] }
|
||||
async-graphql-axum = "5.0.3"
|
||||
axum = "0.6.1"
|
||||
sqlx = { version = "0.6.2", features = [ "runtime-tokio-native-tls", "postgres" ] }
|
||||
sqlx = { version = "0.6.2", features = [ "runtime-tokio-native-tls", "postgres", "chrono" ] }
|
||||
tokio = { version = "1.23.0", features = [ "full" ] }
|
||||
tower-http = { version = "0.3.5", features = ["cors"] }
|
||||
lazy_static = "1.4.0"
|
||||
reqwest = "0.11.13"
|
||||
reqwest = "0.11.13"
|
||||
chrono = "0.4.23"
|
|
@ -1,5 +1,7 @@
|
|||
use async_graphql::{Context, Enum, Object};
|
||||
use crate::utils::ID_TO_WORLD;
|
||||
use async_graphql::{Context, Enum, Object, SimpleObject};
|
||||
use axum::{http::StatusCode, response::IntoResponse, Extension, Json};
|
||||
use chrono::{DateTime, Utc};
|
||||
use sqlx::{query, Pool, Postgres, Row};
|
||||
|
||||
pub async fn get_health(Extension(pool): Extension<Pool<Postgres>>) -> impl IntoResponse {
|
||||
|
@ -53,6 +55,37 @@ enum UpDown {
|
|||
|
||||
pub struct Health {}
|
||||
|
||||
impl Health {
|
||||
async fn most_recent_event_time<'ctx>(
|
||||
&self,
|
||||
ctx: &Context<'ctx>,
|
||||
world_id: i32,
|
||||
) -> (UpDown, Option<DateTime<Utc>>) {
|
||||
let pool = ctx.data::<Pool<Postgres>>().unwrap();
|
||||
|
||||
let events_resp =
|
||||
query("SELECT time FROM analytics WHERE world_id = $1 ORDER BY time DESC LIMIT 1")
|
||||
.bind(world_id)
|
||||
.fetch_one(pool)
|
||||
.await;
|
||||
|
||||
match events_resp {
|
||||
Ok(row) => {
|
||||
let last_event: DateTime<Utc> = row.get(0);
|
||||
|
||||
if last_event < Utc::now() - chrono::Duration::minutes(5) {
|
||||
return (UpDown::Down, None);
|
||||
} else {
|
||||
return (UpDown::Up, Some(last_event));
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
return (UpDown::Down, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reports on the health of Saerro Listening Post
|
||||
#[Object]
|
||||
impl Health {
|
||||
|
@ -104,6 +137,34 @@ impl Health {
|
|||
.map(|_| UpDown::Up)
|
||||
.unwrap_or(UpDown::Down)
|
||||
}
|
||||
|
||||
/// Shows a disclaimer for the worlds check
|
||||
async fn worlds_disclaimer(&self) -> String {
|
||||
"This is a best-effort check. A world reports `DOWN` when it doesn't have new events for 5 minutes. It could be broken, it could be the reality of the game state.".to_string()
|
||||
}
|
||||
|
||||
/// Checks if a world has had any events for the last 5 minutes
|
||||
async fn worlds<'ctx>(&self, ctx: &Context<'ctx>) -> Vec<WorldUpDown> {
|
||||
let mut worlds = Vec::new();
|
||||
for (id, name) in ID_TO_WORLD.iter() {
|
||||
let (status, last_event) = self.most_recent_event_time(ctx, *id).await;
|
||||
worlds.push(WorldUpDown {
|
||||
id: *id,
|
||||
name: name.to_string(),
|
||||
status,
|
||||
last_event,
|
||||
});
|
||||
}
|
||||
worlds
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(SimpleObject)]
|
||||
struct WorldUpDown {
|
||||
id: i32,
|
||||
name: String,
|
||||
status: UpDown,
|
||||
last_event: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
<li>
|
||||
<a
|
||||
id="status_query_link"
|
||||
href="/graphql?query={ health { database ingest ingestReachable } }"
|
||||
href="/graphql?query={ health { database ingest ingestReachable worldsDisclaimer worlds { name status lastEvent } } }"
|
||||
>Current system status</a
|
||||
>
|
||||
(<a
|
||||
|
@ -61,7 +61,13 @@
|
|||
health {
|
||||
database
|
||||
ingest
|
||||
ingestReachable
|
||||
ingestReachable
|
||||
worldsDisclaimer
|
||||
worlds {
|
||||
name
|
||||
status
|
||||
lastEvent
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
<a
|
||||
|
@ -236,10 +242,10 @@
|
|||
</p>
|
||||
<p>For help, please contact us in #api-dev on the PlanetSide 2 Discord.</p>
|
||||
<p>
|
||||
[<a href="https://github.com/genudine/saerro">github</a>] [<a
|
||||
href="https://pstop.harasse.rs"
|
||||
>pstop</a
|
||||
>]
|
||||
[<a href="/ingest.html">ingest stats</a>] [<a
|
||||
href="https://github.com/genudine/saerro"
|
||||
>github</a
|
||||
>] [<a href="https://pstop.harasse.rs">pstop</a>]
|
||||
</p>
|
||||
<script>
|
||||
const runQuery = async (linkId, resultId) => {
|
||||
|
|
19
services/api/src/html/ingest.html
Normal file
19
services/api/src/html/ingest.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Ingest Stats - Saerro Listening Post</title>
|
||||
<meta charset="utf-8" />
|
||||
<style>
|
||||
body {
|
||||
font-family: monospace;
|
||||
background-color: #010101;
|
||||
color: #e0e0e0;
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #cead42;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
<h1>Ingest Stats</h1>
|
||||
<p>sorry wip</p>
|
|
@ -27,6 +27,10 @@ async fn index() -> Html<&'static str> {
|
|||
Html(include_str!("html/index.html"))
|
||||
}
|
||||
|
||||
async fn ingest() -> Html<&'static str> {
|
||||
Html(include_str!("html/ingest.html"))
|
||||
}
|
||||
|
||||
async fn handle_404() -> Html<&'static str> {
|
||||
Html(include_str!("html/404.html"))
|
||||
}
|
||||
|
@ -70,6 +74,7 @@ async fn main() {
|
|||
|
||||
let app = Router::new()
|
||||
.route("/", get(index))
|
||||
.route("/ingest", get(ingest))
|
||||
.route("/health", get(health::get_health))
|
||||
.route(
|
||||
"/graphql",
|
||||
|
|
|
@ -316,9 +316,14 @@ async fn main() {
|
|||
let fused_reader = read
|
||||
.for_each(|msg| async move {
|
||||
let body = &msg.unwrap().to_string();
|
||||
let data: Payload = serde_json::from_str(body).unwrap_or(Payload {
|
||||
payload: Event::default(),
|
||||
});
|
||||
|
||||
let data: Payload = match serde_json::from_str(body) {
|
||||
Ok(data) => data,
|
||||
Err(_) => {
|
||||
// println!("Error: {}; body: {}", e, body.clone());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if data.payload.event_name == "" {
|
||||
return;
|
||||
|
|
Loading…
Add table
Reference in a new issue