discord
This commit is contained in:
parent
329033c439
commit
92c47e8b14
|
@ -1350,6 +1350,16 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gethostname"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
|
@ -2026,6 +2036,7 @@ dependencies = [
|
|||
"config",
|
||||
"enum-iterator 2.1.0",
|
||||
"futures-util",
|
||||
"gethostname 0.4.3",
|
||||
"geyser-grpc-connector",
|
||||
"itertools 0.10.5",
|
||||
"jsonrpsee-types",
|
||||
|
@ -3496,7 +3507,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "efb65329e6716dc0ce5b1d719d6e0052e7ff1179ab361916f256054d6b846ee1"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"gethostname",
|
||||
"gethostname 0.2.3",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"reqwest 0.11.27",
|
||||
|
|
|
@ -35,6 +35,7 @@ anyhow = "1.0.86"
|
|||
reqwest = { version = "0.12.4", features = ["json"] }
|
||||
enum-iterator = "2.1.0"
|
||||
|
||||
gethostname = "0.4.3"
|
||||
url = "2.5.0"
|
||||
config = "0.14.0"
|
||||
itertools = "0.10.5"
|
||||
|
|
|
@ -16,6 +16,8 @@ DISCORD_WEBHOOK=https://discord.com/api/webhooks/abcedfgh
|
|||
cargo run --bin rpc-node-check-alive
|
||||
```
|
||||
|
||||
* `DISCORD_WEBHOOK` is optional
|
||||
|
||||
## Example output
|
||||
```
|
||||
2024-06-05T16:43:44.680699Z INFO rpc_node_check_alive: all tasks started...
|
||||
|
|
|
@ -9,7 +9,7 @@ use std::time::Duration;
|
|||
use futures_util::FutureExt;
|
||||
use geyser_grpc_connector::{GrpcConnectionTimeouts, GrpcSourceConfig, Message};
|
||||
use geyser_grpc_connector::grpc_subscription_autoreconnect_streams::create_geyser_reconnecting_stream;
|
||||
use serde_json::json;
|
||||
use serde_json::{json, Value};
|
||||
use solana_account_decoder::parse_token::spl_token_ids;
|
||||
use solana_rpc_client::nonblocking::rpc_client::RpcClient;
|
||||
use solana_rpc_client::rpc_client::GetConfirmedSignaturesForAddress2Config;
|
||||
|
@ -31,6 +31,7 @@ use yellowstone_grpc_proto::geyser::{SubscribeRequest, SubscribeRequestFilterAcc
|
|||
use yellowstone_grpc_proto::geyser::subscribe_update::UpdateOneof;
|
||||
use anyhow::Context;
|
||||
use enum_iterator::Sequence;
|
||||
use gethostname::gethostname;
|
||||
use solana_account_decoder::UiAccountEncoding;
|
||||
use solana_rpc_client_api::config::{RpcAccountInfoConfig, RpcProgramAccountsConfig};
|
||||
use solana_rpc_client_api::filter::{Memcmp, RpcFilterType};
|
||||
|
@ -57,13 +58,15 @@ enum Check {
|
|||
}
|
||||
|
||||
|
||||
async fn send_webook_discord() {
|
||||
let url = std::env::var("DISCORD_WEBHOOK").unwrap();
|
||||
async fn send_webook_discord(discord_body: Value) {
|
||||
let Ok(url) = std::env::var("DISCORD_WEBHOOK") else {
|
||||
info!("sending to discord is disabled");
|
||||
return;
|
||||
};
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let res = client.post(url)
|
||||
.json(&json!({
|
||||
"content": "Hello, World!"
|
||||
}))
|
||||
.json(&discord_body)
|
||||
.send().await;
|
||||
match res {
|
||||
Ok(_) => {
|
||||
|
@ -79,9 +82,6 @@ async fn send_webook_discord() {
|
|||
async fn main() -> ExitCode {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
|
||||
// send_webook_discord().await;
|
||||
|
||||
// name of rpc node for logging/discord (e.g. hostname)
|
||||
let rpcnode_label = std::env::var("RPCNODE_LABEL").unwrap();
|
||||
|
||||
|
@ -108,10 +108,6 @@ async fn main() -> ExitCode {
|
|||
|
||||
info!("checks enabled for rpcnode <{}>: {:?}", rpcnode_label, checks_enabled);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
let mut all_check_tasks: JoinSet<CheckResult> = JoinSet::new();
|
||||
|
||||
if checks_enabled.contains(&Check::Gpa) {
|
||||
|
@ -150,6 +146,7 @@ async fn main() -> ExitCode {
|
|||
let mut tasks_success = Vec::new();
|
||||
let mut tasks_successful = 0;
|
||||
let mut tasks_timeout = 0;
|
||||
let mut tasks_timedout = Vec::new();
|
||||
let mut tasks_failed = 0;
|
||||
while let Some(res) = all_check_tasks.join_next().await {
|
||||
match res {
|
||||
|
@ -161,6 +158,7 @@ async fn main() -> ExitCode {
|
|||
Ok(CheckResult::Timeout(check)) => {
|
||||
tasks_timeout += 1;
|
||||
warn!("timeout running task <{:?}>", check);
|
||||
tasks_timedout.push(check);
|
||||
}
|
||||
Err(_) => {
|
||||
tasks_failed += 1;
|
||||
|
@ -169,11 +167,15 @@ async fn main() -> ExitCode {
|
|||
}
|
||||
}
|
||||
let tasks_total = tasks_successful + tasks_failed + tasks_timeout;
|
||||
let success = tasks_failed + tasks_timeout == 0;
|
||||
|
||||
assert!(tasks_total > 0, "no results");
|
||||
|
||||
|
||||
if tasks_failed + tasks_timeout > 0 {
|
||||
let discord_body = create_discord_message(&rpcnode_label, checks_enabled, &mut tasks_success, tasks_timedout, success);
|
||||
send_webook_discord(discord_body).await;
|
||||
|
||||
if !success {
|
||||
warn!("rpcnode <{}> - tasks failed ({}) or timed out ({}) of {} total",
|
||||
rpcnode_label, tasks_failed, tasks_timeout, tasks_total);
|
||||
for check in enum_iterator::all::<Check>() {
|
||||
|
@ -181,13 +183,69 @@ async fn main() -> ExitCode {
|
|||
warn!("!! did not complet task <{:?}>", check);
|
||||
}
|
||||
}
|
||||
return ExitCode::SUCCESS;
|
||||
return ExitCode::FAILURE;
|
||||
} else {
|
||||
info!("rpcnode <{}> - all {} tasks completed: {:?}", rpcnode_label, tasks_total, tasks_success);
|
||||
return ExitCode::FAILURE;
|
||||
return ExitCode::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
fn create_discord_message(
|
||||
rpcnode_label: &str, checks_enabled: Vec<Check>, mut tasks_success: &mut Vec<Check>, mut tasks_timedout: Vec<Check>, success: bool) -> Value {
|
||||
let result_per_check = enum_iterator::all::<Check>().map(|check| {
|
||||
let name = format!("{:?}", check);
|
||||
let disabled = !checks_enabled.contains(&check);
|
||||
let timedout = tasks_timedout.contains(&check);
|
||||
let success = tasks_success.contains(&check);
|
||||
let value = if disabled {
|
||||
"disabled"
|
||||
} else if timedout {
|
||||
"timed out"
|
||||
} else if success {
|
||||
"OK"
|
||||
} else {
|
||||
"failed"
|
||||
};
|
||||
json! {
|
||||
{
|
||||
"name": name,
|
||||
"value": value
|
||||
}
|
||||
}
|
||||
}).collect_vec();
|
||||
|
||||
let fields = result_per_check;
|
||||
|
||||
let status_color = if success {
|
||||
0x00FF00
|
||||
} else {
|
||||
0xFC4100
|
||||
};
|
||||
|
||||
let hostname_executed = gethostname();
|
||||
|
||||
let body = json! {
|
||||
{
|
||||
"content": "Automatic RPC Node check script notification",
|
||||
"username": "RPC Node Check",
|
||||
"embeds": [
|
||||
{
|
||||
"title": rpcnode_label,
|
||||
"description": "",
|
||||
"color": status_color,
|
||||
"fields":
|
||||
fields
|
||||
,
|
||||
"footer": {
|
||||
"text": format!("by groovie on {}", hostname_executed.to_string_lossy())
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
body
|
||||
}
|
||||
|
||||
|
||||
fn read_rpc_config() -> Arc<RpcClient> {
|
||||
// http://...
|
||||
|
|
Loading…
Reference in New Issue