From 1a9ecd8b37829a5873b753c607ae91b25a5b3b66 Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Fri, 27 Jun 2025 11:57:26 -0500 Subject: [PATCH 1/4] feat(pyth-lazer-agent): liveness and readiness endpoints --- apps/pyth-lazer-agent/Cargo.lock | 2 +- apps/pyth-lazer-agent/Cargo.toml | 2 +- apps/pyth-lazer-agent/src/http_server.rs | 19 +++++++++++++++++++ apps/pyth-lazer-agent/src/lazer_publisher.rs | 10 +++++++++- apps/pyth-lazer-agent/src/relayer_session.rs | 9 +++++++++ 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/apps/pyth-lazer-agent/Cargo.lock b/apps/pyth-lazer-agent/Cargo.lock index 3834832145..081a98b5ac 100644 --- a/apps/pyth-lazer-agent/Cargo.lock +++ b/apps/pyth-lazer-agent/Cargo.lock @@ -1643,7 +1643,7 @@ dependencies = [ [[package]] name = "pyth-lazer-agent" -version = "0.1.1" +version = "0.1.2" dependencies = [ "anyhow", "backoff", diff --git a/apps/pyth-lazer-agent/Cargo.toml b/apps/pyth-lazer-agent/Cargo.toml index f27178991f..188b2149a5 100644 --- a/apps/pyth-lazer-agent/Cargo.toml +++ b/apps/pyth-lazer-agent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pyth-lazer-agent" -version = "0.1.1" +version = "0.1.2" edition = "2024" [dependencies] diff --git a/apps/pyth-lazer-agent/src/http_server.rs b/apps/pyth-lazer-agent/src/http_server.rs index b4d11565b8..235fdb2af7 100644 --- a/apps/pyth-lazer-agent/src/http_server.rs +++ b/apps/pyth-lazer-agent/src/http_server.rs @@ -28,6 +28,9 @@ pub struct RelayerRequest(pub http::Request); const PUBLISHER_WS_URI: &str = "/v1/publisher"; const PUBLISHER_WS_URI_V2: &str = "/v2/publisher"; +const READINESS_PROBE_PATH: &str = "/ready"; +const LIVENESS_PROBE_PATH: &str = "/live"; + pub async fn run(config: Config, lazer_publisher: LazerPublisher) -> Result<()> { let listener = TcpListener::bind(&config.listen_address).await?; info!("listening on {:?}", &config.listen_address); @@ -74,6 +77,22 @@ async fn request_handler( let request_type = match path { PUBLISHER_WS_URI => Request::PublisherV1, PUBLISHER_WS_URI_V2 => Request::PublisherV2, + LIVENESS_PROBE_PATH => { + let response = Response::builder().status(StatusCode::OK); + return Ok(response.body(FullBody::default())?); + } + READINESS_PROBE_PATH => { + let status = if lazer_publisher + .is_ready + .load(std::sync::atomic::Ordering::Relaxed) + { + StatusCode::OK + } else { + StatusCode::SERVICE_UNAVAILABLE + }; + let response = Response::builder().status(status); + return Ok(response.body(FullBody::default())?); + } _ => { return Ok(Response::builder() .status(StatusCode::NOT_FOUND) diff --git a/apps/pyth-lazer-agent/src/lazer_publisher.rs b/apps/pyth-lazer-agent/src/lazer_publisher.rs index 2d24635e01..a8d9ba4f51 100644 --- a/apps/pyth-lazer-agent/src/lazer_publisher.rs +++ b/apps/pyth-lazer-agent/src/lazer_publisher.rs @@ -14,6 +14,8 @@ use pyth_lazer_publisher_sdk::transaction::{ }; use solana_keypair::read_keypair_file; use std::path::PathBuf; +use std::sync::Arc; +use std::sync::atomic::AtomicBool; use tokio::sync::broadcast; use tokio::{ select, @@ -25,6 +27,7 @@ use tracing::error; #[derive(Clone)] pub struct LazerPublisher { sender: Sender, + pub(crate) is_ready: Arc, } impl LazerPublisher { @@ -66,11 +69,13 @@ impl LazerPublisher { }; let (relayer_sender, _) = broadcast::channel(CHANNEL_CAPACITY); + let is_ready = Arc::new(AtomicBool::new(false)); for url in config.relayer_urls.iter() { let mut task = RelayerSessionTask { url: url.clone(), token: authorization_token.clone(), receiver: relayer_sender.subscribe(), + is_ready: is_ready.clone(), }; tokio::spawn(async move { task.run().await }); } @@ -84,7 +89,10 @@ impl LazerPublisher { signing_key, }; tokio::spawn(async move { task.run().await }); - Self { sender } + Self { + sender, + is_ready: Arc::new(AtomicBool::new(false)), + } } pub async fn push_feed_update(&self, feed_update: FeedUpdate) -> Result<()> { diff --git a/apps/pyth-lazer-agent/src/relayer_session.rs b/apps/pyth-lazer-agent/src/relayer_session.rs index f6fb35e2fe..d89d8b140f 100644 --- a/apps/pyth-lazer-agent/src/relayer_session.rs +++ b/apps/pyth-lazer-agent/src/relayer_session.rs @@ -6,6 +6,8 @@ use futures_util::{SinkExt, StreamExt}; use http::HeaderValue; use protobuf::Message; use pyth_lazer_publisher_sdk::transaction::SignedLazerTransaction; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; use tokio::net::TcpStream; use tokio::select; @@ -63,6 +65,7 @@ pub struct RelayerSessionTask { pub url: Url, pub token: String, pub receiver: broadcast::Receiver, + pub is_ready: Arc, } impl RelayerSessionTask { @@ -116,6 +119,9 @@ impl RelayerSessionTask { ws_sender: relayer_ws_sender, }; + // If we have at least one successful connection, mark as ready. + self.is_ready.store(true, Ordering::Relaxed); + loop { select! { recv_result = self.receiver.recv() => { @@ -174,6 +180,8 @@ mod tests { Ed25519SignatureData, LazerTransaction, SignatureData, SignedLazerTransaction, }; use std::net::SocketAddr; + use std::sync::Arc; + use std::sync::atomic::AtomicBool; use tokio::net::TcpListener; use tokio::sync::{broadcast, mpsc}; use url::Url; @@ -234,6 +242,7 @@ mod tests { url: Url::parse("ws://127.0.0.1:12346").unwrap(), token: "token1".to_string(), receiver: relayer_receiver, + is_ready: Arc::new(AtomicBool::new(false)), }; tokio::spawn(async move { relayer_session_task.run().await }); tokio::time::sleep(std::time::Duration::from_millis(1000)).await; From 9d3c0534201a1d3c543b9deeeae13587e40f3cc8 Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Fri, 27 Jun 2025 12:30:40 -0500 Subject: [PATCH 2/4] add merolish to CODEOWNERS for pyth-lazer-agent --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4e0e9fa374..6e8082d3b8 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,6 +2,7 @@ apps/api-reference @pyth-network/web-team apps/entropy-debugger @pyth-network/web-team apps/insights @pyth-network/web-team apps/staking @pyth-network/web-team +apps/pyth-lazer-agent @merolish packages/component-library @pyth-network/web-team packages/known-publishers @pyth-network/web-team Dockerfile.node @pyth-network/web-team From 4c4d6a9e75480367cd6a9e3d5da789b9e30fbc9e Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Fri, 27 Jun 2025 12:32:34 -0500 Subject: [PATCH 3/4] Fixed Ali's username in CODEOWNERS --- .github/CODEOWNERS | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6e8082d3b8..d245155c69 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -17,11 +17,11 @@ turbo.json @pyth-network/web-team .github/workflows/ci-turbo-build.yml @pyth-network/web-team .github/workflows/ci-turbo-test.yml @pyth-network/web-team -/lazer/contracts/aptos @Riateche @ali-bahjati -/lazer/contracts/evm @Riateche @ali-bahjati -/lazer/contracts/solana @Riateche @ali-bahjati +/lazer/contracts/aptos @Riateche @ali-behjati +/lazer/contracts/evm @Riateche @ali-behjati +/lazer/contracts/solana @Riateche @ali-behjati /lazer/publisher_sdk @darunrs @Riateche -/lazer/sdk/js @ali-bahjati @keyvankhademi +/lazer/sdk/js @ali-behjati @keyvankhademi /lazer/sdk/rust @darunrs @Riateche flake.lock @cprussin From 0ca136374387946111bf812a0488cce9f21b6a5e Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Fri, 27 Jun 2025 12:50:51 -0500 Subject: [PATCH 4/4] oops --- apps/pyth-lazer-agent/src/lazer_publisher.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pyth-lazer-agent/src/lazer_publisher.rs b/apps/pyth-lazer-agent/src/lazer_publisher.rs index a8d9ba4f51..b556f2d765 100644 --- a/apps/pyth-lazer-agent/src/lazer_publisher.rs +++ b/apps/pyth-lazer-agent/src/lazer_publisher.rs @@ -91,7 +91,7 @@ impl LazerPublisher { tokio::spawn(async move { task.run().await }); Self { sender, - is_ready: Arc::new(AtomicBool::new(false)), + is_ready: is_ready.clone(), } }