feat: expose configurations, add retry, make stable
This commit is contained in:
parent
c6e726c430
commit
50ec63a474
11 changed files with 494 additions and 221 deletions
1
pi/pi-service/.envrc
Normal file
1
pi/pi-service/.envrc
Normal file
|
|
@ -0,0 +1 @@
|
|||
use flake
|
||||
161
pi/pi-service/Cargo.lock
generated
161
pi/pi-service/Cargo.lock
generated
|
|
@ -610,9 +610,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.182"
|
||||
version = "0.2.183"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
|
||||
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
|
|
@ -626,15 +626,6 @@ version = "0.8.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.29"
|
||||
|
|
@ -761,29 +752,6 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.2"
|
||||
|
|
@ -851,15 +819,6 @@ version = "6.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.28"
|
||||
|
|
@ -990,12 +949,6 @@ dependencies = [
|
|||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "3.7.0"
|
||||
|
|
@ -1106,16 +1059,6 @@ version = "1.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
|
||||
dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.12"
|
||||
|
|
@ -1130,12 +1073,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
|||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.2"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0"
|
||||
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1243,9 +1186,7 @@ dependencies = [
|
|||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.61.2",
|
||||
|
|
@ -1630,16 +1571,7 @@ version = "0.52.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||
dependencies = [
|
||||
"windows-targets 0.53.5",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1657,31 +1589,14 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.6",
|
||||
"windows_aarch64_msvc 0.52.6",
|
||||
"windows_i686_gnu 0.52.6",
|
||||
"windows_i686_gnullvm 0.52.6",
|
||||
"windows_i686_msvc 0.52.6",
|
||||
"windows_x86_64_gnu 0.52.6",
|
||||
"windows_x86_64_gnullvm 0.52.6",
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows_aarch64_gnullvm 0.53.1",
|
||||
"windows_aarch64_msvc 0.53.1",
|
||||
"windows_i686_gnu 0.53.1",
|
||||
"windows_i686_gnullvm 0.53.1",
|
||||
"windows_i686_msvc 0.53.1",
|
||||
"windows_x86_64_gnu 0.53.1",
|
||||
"windows_x86_64_gnullvm 0.53.1",
|
||||
"windows_x86_64_msvc 0.53.1",
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1690,96 +1605,48 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.51.0"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,6 @@ reqwest = { version = "0.12", features = ["json"] }
|
|||
rppal = "0.22"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio = { version = "1", features = ["rt-multi-thread", "macros", "net", "sync", "signal"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = "0.3"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
|
|
|
|||
|
|
@ -56,6 +56,10 @@
|
|||
{
|
||||
packages.aarch64-linux.default = noisebell;
|
||||
packages.aarch64-linux.noisebell = noisebell;
|
||||
|
||||
devShells.${system}.default = craneLib.devShell {
|
||||
packages = [ pkgs.rust-analyzer ];
|
||||
};
|
||||
};
|
||||
in
|
||||
forSystem "x86_64-linux";
|
||||
|
|
|
|||
|
|
@ -1,16 +1,29 @@
|
|||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use axum::{extract::State, routing::get, Json, Router};
|
||||
use rppal::gpio::{Gpio, Level, Trigger};
|
||||
use serde::Serialize;
|
||||
use tracing::{error, info};
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
struct AppState {
|
||||
is_open: AtomicBool,
|
||||
last_changed: AtomicU64,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct StatusResponse {
|
||||
status: &'static str,
|
||||
timestamp: u64,
|
||||
}
|
||||
|
||||
fn unix_timestamp() -> u64 {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs()
|
||||
}
|
||||
|
||||
fn status_str(is_open: bool) -> &'static str {
|
||||
|
|
@ -21,15 +34,18 @@ fn status_str(is_open: bool) -> &'static str {
|
|||
}
|
||||
}
|
||||
|
||||
async fn get_status(State(is_open): State<Arc<AtomicBool>>) -> Json<StatusResponse> {
|
||||
async fn get_status(State(state): State<Arc<AppState>>) -> Json<StatusResponse> {
|
||||
Json(StatusResponse {
|
||||
status: status_str(is_open.load(Ordering::Relaxed)),
|
||||
status: status_str(state.is_open.load(Ordering::Relaxed)),
|
||||
timestamp: state.last_changed.load(Ordering::Relaxed),
|
||||
})
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
tracing_subscriber::fmt::init();
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
|
||||
.init();
|
||||
|
||||
let gpio_pin: u8 = std::env::var("NOISEBELL_GPIO_PIN")
|
||||
.unwrap_or_else(|_| "17".into())
|
||||
|
|
@ -49,68 +65,136 @@ async fn main() -> Result<()> {
|
|||
let endpoint_url =
|
||||
std::env::var("NOISEBELL_ENDPOINT_URL").context("NOISEBELL_ENDPOINT_URL is required")?;
|
||||
|
||||
let retry_attempts: u32 = std::env::var("NOISEBELL_RETRY_ATTEMPTS")
|
||||
.unwrap_or_else(|_| "3".into())
|
||||
.parse()
|
||||
.context("NOISEBELL_RETRY_ATTEMPTS must be a valid u32")?;
|
||||
|
||||
let retry_base_delay_secs: u64 = std::env::var("NOISEBELL_RETRY_BASE_DELAY_SECS")
|
||||
.unwrap_or_else(|_| "1".into())
|
||||
.parse()
|
||||
.context("NOISEBELL_RETRY_BASE_DELAY_SECS must be a valid u64")?;
|
||||
|
||||
let http_timeout_secs: u64 = std::env::var("NOISEBELL_HTTP_TIMEOUT_SECS")
|
||||
.unwrap_or_else(|_| "10".into())
|
||||
.parse()
|
||||
.context("NOISEBELL_HTTP_TIMEOUT_SECS must be a valid u64")?;
|
||||
|
||||
let bind_address = std::env::var("NOISEBELL_BIND_ADDRESS").unwrap_or_else(|_| "0.0.0.0".into());
|
||||
|
||||
let active_low: bool = std::env::var("NOISEBELL_ACTIVE_LOW")
|
||||
.unwrap_or_else(|_| "true".into())
|
||||
.parse()
|
||||
.context("NOISEBELL_ACTIVE_LOW must be true or false")?;
|
||||
|
||||
info!(gpio_pin, debounce_secs, port, %endpoint_url, "starting noisebell");
|
||||
|
||||
let gpio = Gpio::new().context("failed to initialize GPIO")?;
|
||||
let pin = gpio
|
||||
.get(gpio_pin)
|
||||
.context(format!("failed to get GPIO pin {gpio_pin}"))?
|
||||
.into_input_pullup();
|
||||
.context(format!("failed to get GPIO pin {gpio_pin}"))?;
|
||||
let pin = if active_low {
|
||||
pin.into_input_pullup()
|
||||
} else {
|
||||
pin.into_input_pulldown()
|
||||
};
|
||||
|
||||
let is_open = Arc::new(AtomicBool::new(pin.read() == Level::Low));
|
||||
let open_level = if active_low { Level::Low } else { Level::High };
|
||||
let initial_open = pin.read() == open_level;
|
||||
let state = Arc::new(AppState {
|
||||
is_open: AtomicBool::new(initial_open),
|
||||
last_changed: AtomicU64::new(unix_timestamp()),
|
||||
});
|
||||
|
||||
info!(initial_status = status_str(is_open.load(Ordering::Relaxed)), "GPIO initialized");
|
||||
info!(initial_status = status_str(initial_open), "GPIO initialized");
|
||||
|
||||
// Channel to bridge sync GPIO callback -> async notification task
|
||||
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::<bool>();
|
||||
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::<(bool, u64)>();
|
||||
|
||||
// Set up async interrupt for state changes
|
||||
let state_for_interrupt = is_open.clone();
|
||||
pin.set_async_interrupt(
|
||||
// Sync initial state with the cache on startup
|
||||
let _ = tx.send((initial_open, unix_timestamp()));
|
||||
|
||||
let state_for_interrupt = state.clone();
|
||||
// pin must live for the entire program — rppal runs interrupts on a background
|
||||
// thread tied to the InputPin. If pin drops, the interrupt thread is joined and
|
||||
// monitoring stops. We move it into a binding that lives until main() returns.
|
||||
let _pin = pin;
|
||||
_pin.set_async_interrupt(
|
||||
Trigger::Both,
|
||||
Some(Duration::from_secs(debounce_secs)),
|
||||
move |event| {
|
||||
let new_open = match event.trigger {
|
||||
Trigger::FallingEdge => true,
|
||||
Trigger::RisingEdge => false,
|
||||
Trigger::FallingEdge => active_low,
|
||||
Trigger::RisingEdge => !active_low,
|
||||
_ => return,
|
||||
};
|
||||
let was_open = state_for_interrupt.swap(new_open, Ordering::Relaxed);
|
||||
let was_open = state_for_interrupt.is_open.swap(new_open, Ordering::Relaxed);
|
||||
if was_open != new_open {
|
||||
let _ = tx.send(new_open);
|
||||
let timestamp = unix_timestamp();
|
||||
state_for_interrupt.last_changed.store(timestamp, Ordering::Relaxed);
|
||||
let _ = tx.send((new_open, timestamp));
|
||||
}
|
||||
},
|
||||
)
|
||||
.context("failed to set GPIO interrupt")?;
|
||||
|
||||
// Task that POSTs state changes to the endpoint
|
||||
tokio::spawn(async move {
|
||||
let client = reqwest::Client::new();
|
||||
while let Some(new_open) = rx.recv().await {
|
||||
let status = status_str(new_open);
|
||||
info!(status, "state changed");
|
||||
let notify_handle = tokio::spawn(async move {
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(Duration::from_secs(http_timeout_secs))
|
||||
.build()
|
||||
.expect("failed to build HTTP client");
|
||||
|
||||
if let Err(e) = client
|
||||
.post(&endpoint_url)
|
||||
.json(&serde_json::json!({ "status": status }))
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
error!(%e, "failed to notify endpoint");
|
||||
while let Some((new_open, timestamp)) = rx.recv().await {
|
||||
let status = status_str(new_open);
|
||||
info!(status, timestamp, "state changed");
|
||||
|
||||
let payload = serde_json::json!({ "status": status, "timestamp": timestamp });
|
||||
|
||||
for attempt in 0..=retry_attempts {
|
||||
let result = client.post(&endpoint_url).json(&payload).send().await;
|
||||
match result {
|
||||
Ok(resp) if resp.status().is_success() => break,
|
||||
_ => {
|
||||
let err_msg = match &result {
|
||||
Ok(resp) => format!("HTTP {}", resp.status()),
|
||||
Err(e) => e.to_string(),
|
||||
};
|
||||
if attempt == retry_attempts {
|
||||
error!(error = %err_msg, "failed to notify endpoint after {} attempts", retry_attempts + 1);
|
||||
} else {
|
||||
let delay = Duration::from_secs(
|
||||
retry_base_delay_secs * 2u64.pow(attempt),
|
||||
);
|
||||
warn!(error = %err_msg, attempt = attempt + 1, "notify failed, retrying in {:?}", delay);
|
||||
tokio::time::sleep(delay).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let app = Router::new()
|
||||
.route("/status", get(get_status))
|
||||
.with_state(is_open);
|
||||
.route("/", get(get_status))
|
||||
.with_state(state);
|
||||
|
||||
let listener = tokio::net::TcpListener::bind(("0.0.0.0", port))
|
||||
let listener = tokio::net::TcpListener::bind((&*bind_address, port))
|
||||
.await
|
||||
.context(format!("failed to bind to port {port}"))?;
|
||||
.context(format!("failed to bind to {bind_address}:{port}"))?;
|
||||
|
||||
info!(port, "listening");
|
||||
axum::serve(listener, app).await.context("server error")?;
|
||||
|
||||
let shutdown = tokio::signal::ctrl_c();
|
||||
axum::serve(listener, app)
|
||||
.with_graceful_shutdown(async { shutdown.await.ok(); })
|
||||
.await
|
||||
.context("server error")?;
|
||||
|
||||
info!("shutting down, draining notification queue");
|
||||
// Drop the interrupt to stop producing new messages, then wait
|
||||
// for the notification task to drain remaining messages.
|
||||
drop(_pin);
|
||||
let _ = notify_handle.await;
|
||||
|
||||
info!("shutdown complete");
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue