feat: use ShutdownToken (CancellationToken inside) for nym-api (#5997)

* make nym-api use ShutdownToken instead of TaskClient

* ignore public-api tests if env is not set

* removed default features to avoid pulling in openssl
This commit is contained in:
Jędrzej Stuczyński
2025-09-08 09:45:28 +01:00
committed by GitHub
parent 8e7d1d510d
commit e95aca715c
32 changed files with 219 additions and 209 deletions
Generated
+43 -13
View File
@@ -1373,7 +1373,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [
"lazy_static",
"windows-sys 0.48.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -2352,12 +2352,6 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "dotenv"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]]
name = "dotenvy"
version = "0.15.7"
@@ -4030,7 +4024,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
dependencies = [
"hermit-abi",
"libc",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -4907,7 +4901,7 @@ dependencies = [
"cw3",
"cw4",
"dashmap",
"dotenv",
"dotenvy",
"futures",
"humantime-serde",
"moka",
@@ -4952,6 +4946,7 @@ dependencies = [
"sqlx",
"tempfile",
"tendermint",
"test-with",
"thiserror 2.0.12",
"time",
"tokio",
@@ -8229,6 +8224,28 @@ dependencies = [
"elliptic-curve",
]
[[package]]
name = "proc-macro-error-attr2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
name = "proc-macro-error2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
dependencies = [
"proc-macro-error-attr2",
"proc-macro2",
"quote",
"syn 2.0.104",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
@@ -8397,7 +8414,7 @@ dependencies = [
"once_cell",
"socket2 0.5.10",
"tracing",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -8882,7 +8899,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys 0.4.15",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -10189,7 +10206,7 @@ dependencies = [
"getrandom 0.3.3",
"once_cell",
"rustix 1.0.8",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -10305,6 +10322,19 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "test-with"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0f370b9efbfbbc5f057cbce9888373eaeb146a3095bb8cc869b199c94d15559"
dependencies = [
"proc-macro-error2",
"proc-macro2",
"quote",
"regex",
"syn 2.0.104",
]
[[package]]
name = "testnet-manager"
version = "0.1.0"
@@ -11879,7 +11909,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.48.0",
"windows-sys 0.59.0",
]
[[package]]
+1
View File
@@ -330,6 +330,7 @@ syn = "2"
sysinfo = "0.37.0"
tap = "1.0.1"
tar = "0.4.44"
test-with = { version = "0.15.4", default-features = false }
tempfile = "3.20"
thiserror = "2.0"
time = "0.3.41"
+12
View File
@@ -110,6 +110,7 @@ impl ShutdownToken {
// exposed method with the old name for easier migration
// it will eventually be removed so please try to use `.clone_with_suffix` instead
#[must_use]
#[deprecated(note = "use .clone_with_suffix instead")]
pub fn fork<S: Into<String>>(&self, child_suffix: S) -> Self {
self.clone_with_suffix(child_suffix)
}
@@ -117,6 +118,7 @@ impl ShutdownToken {
// exposed method with the old name for easier migration
// it will eventually be removed so please try to use `.clone().named(name)` instead
#[must_use]
#[deprecated(note = "use .clone().named(name) instead")]
pub fn fork_named<S: Into<String>>(&self, name: S) -> Self {
self.clone().named(name)
}
@@ -232,6 +234,16 @@ impl ShutdownManager {
manager.with_shutdown(async move { cancel_watcher.cancelled().await })
}
pub fn empty_mock() -> Self {
ShutdownManager {
root_token: ShutdownToken::ephemeral(),
legacy_task_manager: None,
shutdown_signals: Default::default(),
tracker: Default::default(),
max_shutdown_duration: Default::default(),
}
}
pub fn with_legacy_task_manager(mut self) -> Self {
let mut legacy_manager =
TaskManager::default().named(format!("{}-legacy", self.root_token.name()));
-1
View File
@@ -119,7 +119,6 @@ exceptions = [
#{ allow = ["Zlib"], crate = "adler32" },
{ allow = ["GPL-3.0"], crate = "nym-api" },
{ allow = ["GPL-3.0"], crate = "nym-gateway" },
{ allow = ["GPL-3.0"], crate = "nym-mixnode" },
{ allow = ["GPL-3.0"], crate = "nym-network-requester" },
{ allow = ["GPL-3.0"], crate = "nym-node" },
{ allow = ["GPL-3.0"], crate = "nym-validator-rewarder" },
+2 -1
View File
@@ -126,7 +126,8 @@ cw3 = { workspace = true }
cw-utils = { workspace = true }
rand_chacha = { workspace = true }
sha2 = { workspace = true }
dotenv = "0.15"
dotenvy = { workspace = true }
test-with = { workspace = true, default-features = false }
[lints]
workspace = true
+6 -6
View File
@@ -11,7 +11,7 @@ use anyhow::{bail, Result};
use nym_coconut_dkg_common::types::{Epoch, EpochId, EpochState};
use nym_crypto::asymmetric::ed25519;
use nym_dkg::bte::keys::KeyPair as DkgKeyPair;
use nym_task::{TaskClient, TaskManager};
use nym_task::{ShutdownManager, ShutdownToken};
use rand::rngs::OsRng;
use rand::{CryptoRng, Rng, RngCore};
use std::path::PathBuf;
@@ -273,7 +273,7 @@ impl<R: RngCore + CryptoRng + Clone> DkgController<R> {
tick_duration < min
}
pub(crate) async fn run(mut self, mut shutdown: TaskClient) {
pub(crate) async fn run(mut self, shutdown: ShutdownToken) {
let mut interval = interval(self.polling_rate);
interval.set_missed_tick_behavior(MissedTickBehavior::Delay);
@@ -282,7 +282,7 @@ impl<R: RngCore + CryptoRng + Clone> DkgController<R> {
let mut last_polled = OffsetDateTime::now_utc();
let mut last_tick_duration = Default::default();
while !shutdown.is_shutdown() {
while !shutdown.is_cancelled() {
tokio::select! {
_ = interval.tick() => {
let now = OffsetDateTime::now_utc();
@@ -300,7 +300,7 @@ impl<R: RngCore + CryptoRng + Clone> DkgController<R> {
error!("failed to update the DKG state: {err}")
}
}
_ = shutdown.recv() => {
_ = shutdown.cancelled() => {
trace!("DkgController: Received shutdown");
}
}
@@ -314,12 +314,12 @@ impl<R: RngCore + CryptoRng + Clone> DkgController<R> {
dkg_bte_keypair: DkgKeyPair,
identity_key: ed25519::PublicKey,
rng: R,
shutdown: &TaskManager,
shutdown_manager: &ShutdownManager,
) -> Result<()>
where
R: Sync + Send + 'static,
{
let shutdown_listener = shutdown.subscribe();
let shutdown_listener = shutdown_manager.clone_token("DKG controller");
let dkg_controller = DkgController::new(
config,
nyxd_client,
+9 -5
View File
@@ -6,7 +6,7 @@ use crate::node_status_api::models::NymApiStorageError;
use crate::support::config::Config;
use crate::support::storage::NymApiStorage;
use nym_ecash_time::ecash_today_date;
use nym_task::TaskClient;
use nym_task::ShutdownToken;
use std::time::Duration;
use time::Date;
use tokio::task::JoinHandle;
@@ -20,11 +20,15 @@ pub struct EcashBackgroundStateCleaner {
verified_tickets_retention_period_days: u32,
storage: NymApiStorage,
task_client: TaskClient,
shutdown_token: ShutdownToken,
}
impl EcashBackgroundStateCleaner {
pub fn new(global_config: &Config, storage: NymApiStorage, task_client: TaskClient) -> Self {
pub fn new(
global_config: &Config,
storage: NymApiStorage,
shutdown_token: ShutdownToken,
) -> Self {
EcashBackgroundStateCleaner {
run_interval: global_config.ecash_signer.debug.stale_data_cleaner_interval,
issued_ticketbooks_retention_period_days: global_config
@@ -36,7 +40,7 @@ impl EcashBackgroundStateCleaner {
.debug
.verified_tickets_retention_period_days,
storage,
task_client,
shutdown_token,
}
}
@@ -68,7 +72,7 @@ impl EcashBackgroundStateCleaner {
let mut ticker = tokio::time::interval(self.run_interval);
loop {
tokio::select! {
_ = self.task_client.recv() => {
_ = self.shutdown_token.cancelled() => {
trace!("EcashBackgroundStateCleaner: Received shutdown");
break;
}
+7 -3
View File
@@ -44,7 +44,7 @@ use nym_ecash_contract_common::deposit::{Deposit, DepositId};
use nym_ecash_contract_common::msg::ExecuteMsg;
use nym_ecash_contract_common::redeem_credential::BATCH_REDEMPTION_PROPOSAL_TITLE;
use nym_ecash_time::{ecash_default_expiration_date, ecash_today_date};
use nym_task::TaskClient;
use nym_task::ShutdownManager;
use nym_ticketbooks_merkle::{IssuedTicketbook, IssuedTicketbooksFullMerkleProof, MerkleLeaf};
use nym_validator_client::nyxd::AccountId;
use nym_validator_client::EcashApiClient;
@@ -126,7 +126,7 @@ impl EcashState {
key_pair: KeyPair,
comm_channel: D,
storage: NymApiStorage,
task_client: TaskClient,
shutdown_manager: &ShutdownManager,
) -> Self
where
C: LocalClient + Send + Sync + 'static,
@@ -135,7 +135,11 @@ impl EcashState {
Self {
config: EcashStateConfig::new(global_config),
background_cleaner_state: BackgroundCleanerState::WaitingStartup(
EcashBackgroundStateCleaner::new(global_config, storage.clone(), task_client),
EcashBackgroundStateCleaner::new(
global_config,
storage.clone(),
shutdown_manager.clone_token("ecash-state-data-cleaner"),
),
),
global: GlobalEcachState::new(contract_address),
local: LocalEcashState::new(
+3 -4
View File
@@ -59,7 +59,7 @@ use nym_crypto::asymmetric::ed25519;
use nym_dkg::{NodeIndex, Threshold};
use nym_ecash_contract_common::blacklist::{BlacklistedAccountResponse, Blacklisting};
use nym_ecash_contract_common::deposit::{Deposit, DepositId, DepositResponse};
use nym_task::TaskClient;
use nym_task::ShutdownManager;
use nym_validator_client::nym_api::routes::{
ECASH_BLIND_SIGN, ECASH_ISSUED_TICKETBOOKS_CHALLENGE_COMMITMENT, ECASH_ISSUED_TICKETBOOKS_FOR,
ECASH_ROUTES, V1_API_VERSION,
@@ -1348,7 +1348,7 @@ impl TestFixture {
staged_key_pair,
comm_channel,
storage.clone(),
TaskClient::dummy(),
&ShutdownManager::empty_mock(),
);
// ideally this would have been generic, but that's way too much work
@@ -1489,7 +1489,6 @@ mod credential_tests {
use super::*;
use crate::ecash::storage::EcashStorageExt;
use axum::http::StatusCode;
use nym_task::TaskClient;
use nym_ticketbooks_merkle::MerkleLeaf;
#[tokio::test]
@@ -1580,7 +1579,7 @@ mod credential_tests {
staged_key_pair,
comm_channel,
storage.clone(),
TaskClient::dummy(),
&ShutdownManager::empty_mock(),
);
let deposit_id = 42;
+14 -11
View File
@@ -21,7 +21,7 @@ use crate::support::storage::NymApiStorage;
use error::RewardingError;
pub(crate) use helpers::RewardedNodeWithParams;
use nym_mixnet_contract_common::{CurrentIntervalResponse, Interval};
use nym_task::{TaskClient, TaskManager};
use nym_task::{ShutdownManager, ShutdownToken};
use std::time::Duration;
use tokio::time::sleep;
use tracing::{error, info, trace, warn};
@@ -164,7 +164,7 @@ impl EpochAdvancer {
Ok(())
}
async fn wait_until_epoch_end(&mut self, shutdown: &mut TaskClient) -> Option<Interval> {
async fn wait_until_epoch_end(&mut self, shutdown_token: &ShutdownToken) -> Option<Interval> {
const POLL_INTERVAL: Duration = Duration::from_secs(120);
loop {
@@ -175,7 +175,7 @@ impl EpochAdvancer {
_ = sleep(POLL_INTERVAL) => {
continue
},
_ = shutdown.recv() => {
_ = shutdown_token.cancelled() => {
trace!("wait_until_epoch_end: Received shutdown");
break None
}
@@ -203,7 +203,7 @@ impl EpochAdvancer {
_ = sleep(wait_time) => {
},
_ = shutdown.recv() => {
_ = shutdown_token.cancelled() => {
trace!("wait_until_epoch_end: Received shutdown");
break None
}
@@ -212,7 +212,10 @@ impl EpochAdvancer {
}
}
pub(crate) async fn run(&mut self, mut shutdown: TaskClient) -> Result<(), RewardingError> {
pub(crate) async fn run(
&mut self,
shutdown_token: ShutdownToken,
) -> Result<(), RewardingError> {
info!("waiting for initial contract cache values before we can start rewarding");
self.nym_contract_cache
.naive_wait_for_initial_values()
@@ -221,8 +224,8 @@ impl EpochAdvancer {
info!("waiting for initial self-described cache values before we can start rewarding");
self.described_cache.naive_wait_for_initial_values().await;
while !shutdown.is_shutdown() {
let interval_details = match self.wait_until_epoch_end(&mut shutdown).await {
while !shutdown_token.is_cancelled() {
let interval_details = match self.wait_until_epoch_end(&shutdown_token).await {
// received a shutdown
None => return Ok(()),
Some(interval) => interval,
@@ -243,17 +246,17 @@ impl EpochAdvancer {
status_cache: &NodeStatusCache,
described_cache: SharedCache<DescribedNodes>,
storage: &NymApiStorage,
shutdown: &TaskManager,
shutdown_manager: &ShutdownManager,
) {
let mut rewarded_set_updater = EpochAdvancer::new(
let mut epoch_advancer = EpochAdvancer::new(
nyxd_client,
nym_contract_cache.to_owned(),
status_cache.to_owned(),
described_cache,
storage.to_owned(),
);
let shutdown_listener = shutdown.subscribe();
tokio::spawn(async move { rewarded_set_updater.run(shutdown_listener).await });
let shutdown_listener = shutdown_manager.clone_token("epoch-advancer");
tokio::spawn(async move { epoch_advancer.run(shutdown_listener).await });
}
}
+6 -6
View File
@@ -4,7 +4,7 @@
use crate::mixnet_contract_cache::cache::MixnetContractCache;
use crate::support::caching::refresher::{CacheUpdateWatcher, RefreshRequester};
use nym_mixnet_contract_common::{Interval, KeyRotationState};
use nym_task::TaskClient;
use nym_task::ShutdownToken;
use time::OffsetDateTime;
use tracing::{debug, error, info, trace};
@@ -110,14 +110,14 @@ impl KeyRotationController {
}
}
async fn run(&mut self, mut task_client: TaskClient) {
async fn run(&mut self, shutdown_token: ShutdownToken) {
self.contract_cache.naive_wait_for_initial_values().await;
self.handle_contract_cache_update().await;
while !task_client.is_shutdown() {
while !shutdown_token.is_cancelled() {
tokio::select! {
biased;
_ = task_client.recv() => {
_ = shutdown_token.cancelled() => {
trace!("KeyRotationController: Received shutdown");
}
_ = self.contract_cache_watcher.changed() => {
@@ -129,8 +129,8 @@ impl KeyRotationController {
trace!("KeyRotationController: exiting")
}
pub(crate) fn start(mut self, task_client: TaskClient) {
tokio::spawn(async move { self.run(task_client).await });
pub(crate) fn start(mut self, shutdown_token: ShutdownToken) {
tokio::spawn(async move { self.run(shutdown_token).await });
}
}
+5 -5
View File
@@ -25,7 +25,7 @@ use nym_crypto::asymmetric::{ed25519, x25519};
use nym_sphinx::acknowledgements::AckKey;
use nym_sphinx::params::PacketType;
use nym_sphinx::receiver::MessageReceiver;
use nym_task::TaskManager;
use nym_task::ShutdownManager;
use std::sync::Arc;
use tracing::info;
@@ -167,12 +167,12 @@ impl<R: MessageReceiver + Send + Sync + 'static> NetworkMonitorRunnables<R> {
// TODO: note, that is not exactly doing what we want, because when
// `ReceivedProcessor` is constructed, it already spawns a future
// this needs to be refactored!
pub(crate) fn spawn_tasks(self, shutdown: &TaskManager) {
pub(crate) fn spawn_tasks(self, shutdown: &ShutdownManager) {
let mut packet_receiver = self.packet_receiver;
let mut monitor = self.monitor;
let shutdown_listener = shutdown.subscribe();
let shutdown_listener = shutdown.clone_token("NM-packet-receiver");
tokio::spawn(async move { packet_receiver.run(shutdown_listener).await });
let shutdown_listener = shutdown.subscribe();
let shutdown_listener = shutdown.clone_token("NM-main");
tokio::spawn(async move { monitor.run(shutdown_listener).await });
}
}
@@ -241,7 +241,7 @@ pub(crate) async fn start<R: MessageReceiver + Send + Sync + 'static>(
node_status_cache: NodeStatusCache,
storage: &NymApiStorage,
nyxd_client: nyxd::Client,
shutdown: &TaskManager,
shutdown: &ShutdownManager,
) {
let monitor_builder = setup(
config,
+5 -5
View File
@@ -12,7 +12,7 @@ use crate::support::config;
use nym_mixnet_contract_common::NodeId;
use nym_sphinx::params::PacketType;
use nym_sphinx::receiver::MessageReceiver;
use nym_task::TaskClient;
use nym_task::ShutdownToken;
use std::collections::{HashMap, HashSet};
use tokio::time::{sleep, Duration, Instant};
use tracing::{debug, error, info, trace};
@@ -325,7 +325,7 @@ impl<R: MessageReceiver + Send + Sync> Monitor<R> {
self.test_nonce += 1;
}
pub(crate) async fn run(&mut self, mut shutdown: TaskClient) {
pub(crate) async fn run(&mut self, shutdown_token: ShutdownToken) {
self.received_processor.start_receiving();
// wait for validator cache to be ready
@@ -334,18 +334,18 @@ impl<R: MessageReceiver + Send + Sync> Monitor<R> {
.await;
let mut run_interval = tokio::time::interval(self.run_interval);
while !shutdown.is_shutdown() {
while !shutdown_token.is_cancelled() {
tokio::select! {
_ = run_interval.tick() => {
tokio::select! {
biased;
_ = shutdown.recv() => {
_ = shutdown_token.cancelled() => {
trace!("UpdateHandler: Received shutdown");
}
_ = self.test_run() => (),
}
}
_ = shutdown.recv() => {
_ = shutdown_token.cancelled() => {
trace!("UpdateHandler: Received shutdown");
}
}
@@ -7,7 +7,7 @@ use futures::channel::mpsc;
use futures::StreamExt;
use nym_crypto::asymmetric::ed25519;
use nym_gateway_client::{AcknowledgementReceiver, MixnetMessageReceiver};
use nym_task::TaskClient;
use nym_task::ShutdownToken;
use tracing::{error, trace};
pub(crate) type GatewayClientUpdateSender = mpsc::UnboundedSender<GatewayClientUpdate>;
@@ -57,11 +57,11 @@ impl PacketReceiver {
}
}
pub(crate) async fn run(&mut self, mut shutdown: TaskClient) {
while !shutdown.is_shutdown() {
pub(crate) async fn run(&mut self, shutdown_token: ShutdownToken) {
while !shutdown_token.is_cancelled() {
tokio::select! {
biased;
_ = shutdown.recv() => {
_ = shutdown_token.cancelled() => {
trace!("UpdateHandler: Received shutdown");
}
// unwrap here is fine as it can only return a `None` if the PacketSender has died
@@ -10,7 +10,7 @@ use crate::support::caching::cache::SharedCache;
use crate::support::caching::refresher::CacheRefresher;
use crate::support::{config, nyxd};
use anyhow::bail;
use nym_task::TaskManager;
use nym_task::ShutdownManager;
pub(crate) mod data;
pub(crate) mod refresher;
@@ -19,7 +19,7 @@ pub(crate) async fn start_cache_refresher(
config: &config::PerformanceProvider,
nyxd_client: nyxd::Client,
mixnet_contract_cache: MixnetContractCache,
task_manager: &TaskManager,
shutdown_manager: &ShutdownManager,
) -> anyhow::Result<SharedCache<PerformanceContractCacheData>> {
let values_to_retain = config.debug.max_epoch_entries_to_retain;
@@ -45,7 +45,7 @@ pub(crate) async fn start_cache_refresher(
.with_update_fn(move |main_cache, update| {
refresher_update_fn(main_cache, update, values_to_retain)
})
.start(task_manager.subscribe_named("performance-contract-cache-refresher"));
.start(shutdown_manager.clone_token("performance-contract-cache-refresher"));
Ok(warmed_up_cache)
}
+7 -7
View File
@@ -21,7 +21,7 @@ use nym_api_requests::models::{
NodePerformance,
};
use nym_mixnet_contract_common::{NodeId, NymNodeDetails, RewardingParams};
use nym_task::TaskClient;
use nym_task::ShutdownToken;
use nym_topology::CachedEpochRewardedSet;
use std::collections::HashMap;
use std::time::Duration;
@@ -66,20 +66,20 @@ impl NodeStatusCacheRefresher {
}
/// Runs the node status cache refresher task.
pub async fn run(&mut self, mut shutdown: TaskClient) {
pub async fn run(&mut self, shutdown_token: ShutdownToken) {
let mut last_update = OffsetDateTime::now_utc();
let mut fallback_interval = time::interval(self.fallback_caching_interval);
while !shutdown.is_shutdown() {
while !shutdown_token.is_cancelled() {
tokio::select! {
biased;
_ = shutdown.recv() => {
_ = shutdown_token.cancelled() => {
trace!("NodeStatusCacheRefresher: Received shutdown");
}
// Update node status cache when the contract cache / describe cache is updated
Ok(_) = self.mixnet_contract_cache_listener.changed() => {
tokio::select! {
_ = self.maybe_refresh(&mut fallback_interval, &mut last_update) => (),
_ = shutdown.recv() => {
_ = shutdown_token.cancelled() => {
trace!("NodeStatusCacheRefresher: Received shutdown");
}
}
@@ -87,7 +87,7 @@ impl NodeStatusCacheRefresher {
Ok(_) = self.describe_cache_listener.changed() => {
tokio::select! {
_ = self.maybe_refresh(&mut fallback_interval, &mut last_update) => (),
_ = shutdown.recv() => {
_ = shutdown_token.cancelled() => {
trace!("NodeStatusCacheRefresher: Received shutdown");
}
}
@@ -97,7 +97,7 @@ impl NodeStatusCacheRefresher {
_ = fallback_interval.tick() => {
tokio::select! {
_ = self.maybe_refresh(&mut fallback_interval, &mut last_update) => (),
_ = shutdown.recv() => {
_ = shutdown_token.cancelled() => {
trace!("NodeStatusCacheRefresher: Received shutdown");
}
}
+3 -3
View File
@@ -11,7 +11,7 @@ use crate::{
support::{self},
};
pub(crate) use cache::NodeStatusCache;
use nym_task::TaskManager;
use nym_task::ShutdownManager;
use std::time::Duration;
use tokio::sync::watch;
@@ -39,7 +39,7 @@ pub(crate) fn start_cache_refresh(
performance_provider: Box<dyn NodePerformanceProvider + Send + Sync>,
nym_contract_cache_listener: watch::Receiver<support::caching::CacheNotification>,
described_cache_cache_listener: watch::Receiver<support::caching::CacheNotification>,
shutdown: &TaskManager,
shutdown_manager: &ShutdownManager,
) {
let mut nym_api_cache_refresher = NodeStatusCacheRefresher::new(
node_status_cache_state.to_owned(),
@@ -50,6 +50,6 @@ pub(crate) fn start_cache_refresh(
described_cache_cache_listener,
performance_provider,
);
let shutdown_listener = shutdown.subscribe();
let shutdown_listener = shutdown_manager.clone_token("node-status-refresher");
tokio::spawn(async move { nym_api_cache_refresher.run(shutdown_listener).await });
}
@@ -6,7 +6,7 @@ use crate::node_status_api::models::{
};
use crate::node_status_api::ONE_DAY;
use crate::storage::NymApiStorage;
use nym_task::{TaskClient, TaskManager};
use nym_task::{ShutdownManager, ShutdownToken};
use std::time::Duration;
use time::macros::time;
use time::{OffsetDateTime, PrimitiveDateTime};
@@ -70,7 +70,7 @@ impl HistoricalUptimeUpdater {
Ok(())
}
pub(crate) async fn run(&self, mut shutdown: TaskClient) {
pub(crate) async fn run(&self, shutdown_token: ShutdownToken) {
// update uptimes at 23:00 UTC each day so that we'd have data from the actual [almost] whole day
// and so that we would avoid the edge case of starting validator API at 23:59 and having some
// nodes update for different days
@@ -98,10 +98,10 @@ impl HistoricalUptimeUpdater {
let start = Instant::now() + time_left;
let mut interval = interval_at(start, ONE_DAY);
while !shutdown.is_shutdown() {
while !shutdown_token.is_cancelled() {
tokio::select! {
biased;
_ = shutdown.recv() => {
_ = shutdown_token.cancelled() => {
trace!("UpdateHandler: Received shutdown");
}
_ = interval.tick() => {
@@ -116,9 +116,9 @@ impl HistoricalUptimeUpdater {
}
}
pub(crate) fn start(storage: NymApiStorage, shutdown: &TaskManager) {
pub(crate) fn start(storage: NymApiStorage, shutdown: &ShutdownManager) {
let uptime_updater = HistoricalUptimeUpdater::new(storage);
let shutdown_listener = shutdown.subscribe();
let shutdown_listener = shutdown.child_token("uptime-updater");
tokio::spawn(async move { uptime_updater.run(shutdown_listener).await });
}
}
+3 -3
View File
@@ -6,7 +6,7 @@ use crate::signers_cache::cache::SignersCacheData;
use crate::support::caching::cache::SharedCache;
use crate::support::caching::refresher::CacheRefresher;
use crate::support::{config, nyxd};
use nym_task::TaskManager;
use nym_task::ShutdownManager;
pub(crate) mod cache;
pub(crate) mod handlers;
@@ -14,7 +14,7 @@ pub(crate) mod handlers;
pub(crate) fn start_refresher(
config: &config::SignersCache,
nyxd_client: nyxd::Client,
task_manager: &TaskManager,
shutdown_manager: &ShutdownManager,
) -> SharedCache<SignersCacheData> {
let refresher = CacheRefresher::new(
SignersCacheDataProvider::new(nyxd_client),
@@ -23,7 +23,7 @@ pub(crate) fn start_refresher(
.named("signers-cache-refresher");
let shared_cache = refresher.get_shared_cache();
refresher.start_with_delay(
task_manager.subscribe_named("signers-cache-refresher"),
shutdown_manager.clone_token("signers-cache-refresher"),
config.debug.refresher_start_delay,
);
shared_cache
+15 -15
View File
@@ -4,7 +4,7 @@
use crate::support::caching::cache::SharedCache;
use crate::support::caching::CacheNotification;
use async_trait::async_trait;
use nym_task::TaskClient;
use nym_task::ShutdownToken;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::{watch, Notify};
@@ -223,33 +223,33 @@ where
}
}
pub async fn refresh(&mut self, task_client: &mut TaskClient) {
pub async fn refresh(&mut self, shutdown_token: &ShutdownToken) {
info!("{}: refreshing cache state", self.name);
tokio::select! {
biased;
_ = task_client.recv() => {
_ = shutdown_token.cancelled() => {
trace!("{}: Received shutdown while refreshing cache", self.name)
}
_ = self.do_refresh_cache() => (),
}
}
pub async fn run(&mut self, mut task_client: TaskClient) {
pub async fn run(&mut self, shutdown_token: ShutdownToken) {
self.provider.wait_until_ready().await;
let mut refresh_interval = interval(self.refreshing_interval);
while !task_client.is_shutdown() {
while !shutdown_token.is_cancelled() {
tokio::select! {
biased;
_ = task_client.recv() => {
_ = shutdown_token.cancelled() => {
trace!("{}: Received shutdown", self.name)
}
_ = refresh_interval.tick() => self.refresh(&mut task_client).await,
_ = refresh_interval.tick() => self.refresh(&shutdown_token).await,
// note: `Notify` is not cancellation safe, HOWEVER, there's only one listener,
// so it doesn't matter if we lose our queue position
_ = self.refresh_requester.0.notified() => {
self.refresh(&mut task_client).await;
self.refresh(&shutdown_token).await;
// since we just performed the full request, we can reset our existing interval
refresh_interval.reset();
}
@@ -257,16 +257,16 @@ where
}
}
pub fn start(mut self, task_client: TaskClient)
pub fn start(mut self, shutdown_token: ShutdownToken)
where
T: Send + Sync + 'static,
E: Send + Sync + 'static,
S: Send + Sync + 'static,
{
tokio::spawn(async move { self.run(task_client).await });
tokio::spawn(async move { self.run(shutdown_token).await });
}
pub fn start_with_delay(mut self, mut task_client: TaskClient, delay: Duration)
pub fn start_with_delay(mut self, shutdown_token: ShutdownToken, delay: Duration)
where
T: Send + Sync + 'static,
E: Send + Sync + 'static,
@@ -276,24 +276,24 @@ where
let sleep = tokio::time::sleep(delay);
tokio::select! {
biased;
_ = task_client.recv() => {
_ = shutdown_token.cancelled() => {
trace!("{}: Received shutdown", self.name);
return
}
_ = sleep => {},
}
self.run(task_client).await
self.run(shutdown_token).await
});
}
pub fn start_with_watcher(self, task_client: TaskClient) -> CacheUpdateWatcher
pub fn start_with_watcher(self, shutdown_token: ShutdownToken) -> CacheUpdateWatcher
where
T: Send + Sync + 'static,
E: Send + Sync + 'static,
S: Send + Sync + 'static,
{
let receiver = self.update_watcher();
self.start(task_client);
self.start(shutdown_token);
receiver
}
}
+30 -51
View File
@@ -27,7 +27,7 @@ use crate::support::http::state::chain_status::ChainStatusCache;
use crate::support::http::state::contract_details::ContractDetailsCache;
use crate::support::http::state::force_refresh::ForcedRefresh;
use crate::support::http::state::AppState;
use crate::support::http::{RouterBuilder, ShutdownHandles, TASK_MANAGER_TIMEOUT_S};
use crate::support::http::{RouterBuilder, TASK_MANAGER_TIMEOUT_S};
use crate::support::nyxd;
use crate::support::storage::runtime_migrations::m001_directory_services_v2_1::migrate_to_directory_services_v2_1;
use crate::support::storage::NymApiStorage;
@@ -39,12 +39,12 @@ use crate::{
use anyhow::{bail, Context};
use nym_config::defaults::NymNetworkDetails;
use nym_sphinx::receiver::SphinxMessageReceiver;
use nym_task::TaskManager;
use nym_task::ShutdownManager;
use nym_validator_client::nyxd::Coin;
use std::net::SocketAddr;
use std::sync::Arc;
use tokio_util::sync::CancellationToken;
use tracing::{error, info};
use std::time::Duration;
use tracing::info;
#[derive(clap::Args, Debug)]
pub(crate) struct Args {
@@ -119,8 +119,9 @@ pub(crate) struct Args {
pub(crate) allow_illegal_ips: bool,
}
async fn start_nym_api_tasks(config: &Config) -> anyhow::Result<ShutdownHandles> {
let task_manager = TaskManager::new(TASK_MANAGER_TIMEOUT_S);
async fn start_nym_api_tasks(config: &Config) -> anyhow::Result<ShutdownManager> {
let shutdown_manager = ShutdownManager::new("nym-api")
.with_shutdown_duration(Duration::from_secs(TASK_MANAGER_TIMEOUT_S));
let nyxd_client = nyxd::Client::new(config)?;
let connected_nyxd = config.get_nyxd_url();
@@ -171,7 +172,7 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result<ShutdownHandles>
ecash_keypair_wrapper.clone(),
comm_channel,
storage.clone(),
task_manager.subscribe_named("ecash-state-data-cleaner"),
&shutdown_manager,
);
// if ecash signer is enabled, there are additional constraints on the nym-api,
@@ -204,7 +205,11 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result<ShutdownHandles>
// check if signers cache is enabled, and if so, start the refresher
let ecash_signers_cache = if config.signers_cache.enabled {
signers_cache::start_refresher(&config.signers_cache, nyxd_client.clone(), &task_manager)
signers_cache::start_refresher(
&config.signers_cache,
nyxd_client.clone(),
&shutdown_manager,
)
} else {
SharedCache::new()
};
@@ -244,7 +249,7 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result<ShutdownHandles>
let describe_cache_refresh_requester = describe_cache_refresher.refresh_requester();
let describe_cache_watcher = describe_cache_refresher
.start_with_watcher(task_manager.subscribe_named("node-self-described-data-refresher"));
.start_with_watcher(shutdown_manager.clone_token("node-self-described-data-refresher"));
let performance_provider = if config.performance_provider.use_performance_contract_data {
if network_details
@@ -260,7 +265,7 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result<ShutdownHandles>
&config.performance_provider,
nyxd_client.clone(),
mixnet_contract_cache_state.clone(),
&task_manager,
&shutdown_manager,
)
.await?;
let provider = ContractPerformanceProvider::new(
@@ -281,8 +286,8 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result<ShutdownHandles>
&mixnet_contract_cache_state.clone(),
nyxd_client.clone(),
);
let contract_cache_watcher =
mixnet_contract_cache_refresher.start_with_watcher(task_manager.subscribe());
let contract_cache_watcher = mixnet_contract_cache_refresher
.start_with_watcher(shutdown_manager.clone_token("contracts-data-refresher"));
node_status_api::start_cache_refresh(
&config.node_status_api,
@@ -292,7 +297,7 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result<ShutdownHandles>
performance_provider,
contract_cache_watcher.clone(),
describe_cache_watcher,
&task_manager,
&shutdown_manager,
);
// start dkg task
@@ -306,7 +311,7 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result<ShutdownHandles>
dkg_bte_keypair,
identity_public_key,
rand::rngs::OsRng,
&task_manager,
&shutdown_manager,
)?;
}
@@ -323,11 +328,11 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result<ShutdownHandles>
node_status_cache_state.clone(),
&storage,
nyxd_client.clone(),
&task_manager,
&shutdown_manager,
)
.await;
HistoricalUptimeUpdater::start(storage.to_owned(), &task_manager);
HistoricalUptimeUpdater::start(storage.to_owned(), &shutdown_manager);
}
// start 'rewarding' if its enabled and there exists source for performance data
@@ -339,7 +344,7 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result<ShutdownHandles>
&node_status_cache_state,
described_nodes_cache.clone(),
&storage,
&task_manager,
&shutdown_manager,
);
}
@@ -350,24 +355,22 @@ async fn start_nym_api_tasks(config: &Config) -> anyhow::Result<ShutdownHandles>
contract_cache_watcher,
mixnet_contract_cache_state,
)
.start(task_manager.subscribe_named("KeyRotationController"));
.start(shutdown_manager.clone_token("KeyRotationController"));
let bind_address = config.base.bind_address.to_owned();
let server = router.build_server(&bind_address).await?;
let cancellation_token = CancellationToken::new();
let shutdown_button = cancellation_token.clone();
let axum_shutdown_receiver = cancellation_token.cancelled_owned();
let server_handle = tokio::spawn(async move {
let http_shutdown = shutdown_manager.clone_token("axum-http");
tokio::spawn(async move {
{
info!("Started Axum HTTP V2 server on {bind_address}");
server.run(axum_shutdown_receiver).await
server.run(http_shutdown).await
}
});
let shutdown = ShutdownHandles::new(task_manager, server_handle, shutdown_button);
shutdown_manager.close();
Ok(shutdown)
Ok(shutdown_manager)
}
pub(crate) async fn execute(args: Args) -> anyhow::Result<()> {
@@ -378,32 +381,8 @@ pub(crate) async fn execute(args: Args) -> anyhow::Result<()> {
config.validate()?;
let mut axum_shutdown = start_nym_api_tasks(&config).await?;
// it doesn't matter which server catches the interrupt: it needs only be caught once
if let Err(err) = axum_shutdown.task_manager_mut().catch_interrupt().await {
error!("Error stopping axum tasks: {err}");
}
info!("Stopping nym API");
axum_shutdown.task_manager_mut().signal_shutdown().ok();
axum_shutdown.task_manager_mut().wait_for_shutdown().await;
let running_server = axum_shutdown.shutdown_axum();
match running_server.await {
Ok(Ok(_)) => {
info!("Axum HTTP server shut down without errors");
}
Ok(Err(err)) => {
error!("Axum HTTP server terminated with: {err}");
anyhow::bail!(err)
}
Err(err) => {
error!("Server task panicked: {err}");
}
};
let shutdown_manager = start_nym_api_tasks(&config).await?;
shutdown_manager.run_until_shutdown().await;
Ok(())
}
-51
View File
@@ -1,10 +1,6 @@
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use nym_task::TaskManager;
use tokio::task::JoinHandle;
use tokio_util::sync::CancellationToken;
pub(crate) mod helpers;
pub(crate) mod openapi;
pub(crate) mod router;
@@ -13,50 +9,3 @@ pub(crate) mod state;
pub(crate) use router::RouterBuilder;
pub(crate) const TASK_MANAGER_TIMEOUT_S: u64 = 10;
/// Shutdown goes 2 directions:
/// 1. signal background tasks to gracefully finish
/// 2. signal server itself
///
/// These are done through separate shutdown handles. Of course, shut down server
/// AFTER you have shut down BG tasks (or past their grace period).
pub(crate) struct ShutdownHandles {
task_manager: TaskManager,
axum_shutdown_button: ShutdownAxum,
/// Tokio JoinHandle for axum server's task
axum_join_handle: AxumJoinHandle,
}
impl ShutdownHandles {
/// Cancellation token is given to Axum server constructor. When the token
/// receives a shutdown signal, Axum server will shut down gracefully.
pub(crate) fn new(
task_manager: TaskManager,
axum_server_handle: AxumJoinHandle,
shutdown_button: CancellationToken,
) -> Self {
Self {
task_manager,
axum_shutdown_button: ShutdownAxum(shutdown_button.clone()),
axum_join_handle: axum_server_handle,
}
}
pub(crate) fn task_manager_mut(&mut self) -> &mut TaskManager {
&mut self.task_manager
}
/// Signal server to shut down, then return join handle to its
/// `tokio` task
///
/// https://tikv.github.io/doc/tokio/task/struct.JoinHandle.html
#[must_use]
pub(crate) fn shutdown_axum(self) -> AxumJoinHandle {
self.axum_shutdown_button.0.cancel();
self.axum_join_handle
}
}
struct ShutdownAxum(CancellationToken);
type AxumJoinHandle = JoinHandle<std::io::Result<()>>;
+3 -4
View File
@@ -19,8 +19,8 @@ use axum::routing::get;
use axum::Router;
use core::net::SocketAddr;
use nym_http_api_common::middleware::logging::log_request_info;
use nym_task::ShutdownToken;
use tokio::net::TcpListener;
use tokio_util::sync::WaitForCancellationFutureOwned;
use tower_http::cors::CorsLayer;
use utoipa::OpenApi;
use utoipa_swagger_ui::SwaggerUi;
@@ -131,14 +131,13 @@ pub(crate) struct ApiHttpServer {
}
impl ApiHttpServer {
pub async fn run(self, receiver: WaitForCancellationFutureOwned) -> Result<(), std::io::Error> {
// into_make_service_with_connect_info allows us to see client ip address
pub async fn run(self, shutdown_token: ShutdownToken) -> Result<(), std::io::Error> {
axum::serve(
self.listener,
self.router
.into_make_service_with_connect_info::<SocketAddr>(),
)
.with_graceful_shutdown(receiver)
.with_graceful_shutdown(async move { shutdown_token.cancelled().await })
.await
}
}
+2
View File
@@ -1,6 +1,7 @@
use crate::utils::{base_url, make_request, validate_json_response};
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_health() -> Result<(), String> {
let url = format!("{}/v1/api-status/health", base_url()?);
let res = make_request(&url).await?;
@@ -11,6 +12,7 @@ async fn test_health() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_build_information() -> Result<(), String> {
let url = format!("{}/v1/api-status/build-information", base_url()?);
let res = make_request(&url).await?;
@@ -1,6 +1,7 @@
use crate::utils::{base_url, make_request, validate_json_response};
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_circulating_supply() -> Result<(), String> {
let url = format!("{}/v1/circulating-supply", base_url()?);
let res = make_request(&url).await?;
@@ -14,6 +15,7 @@ async fn test_get_circulating_supply() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_circulating_supply_value() -> Result<(), String> {
let url = format!(
"{}/v1/circulating-supply/circulating-supply-value",
@@ -32,6 +34,7 @@ async fn test_get_circulating_supply_value() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_total_supply_value() -> Result<(), String> {
let url = format!("{}/v1/circulating-supply/total-supply-value", base_url()?);
let res = make_request(&url).await?;
@@ -1,6 +1,7 @@
use crate::utils::{base_url, make_request, validate_json_response};
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_current_epoch() -> Result<(), String> {
let url = format!("{}/v1/epoch/current", base_url()?);
let res = make_request(&url).await?;
@@ -19,6 +20,7 @@ async fn test_get_current_epoch() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_reward_params() -> Result<(), String> {
let url = format!("{}/v1/epoch/reward_params", base_url()?);
let res = make_request(&url).await?;
+4
View File
@@ -1,6 +1,7 @@
use crate::utils::{base_url, test_client, validate_json_response};
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_chain_status() -> Result<(), String> {
let url = format!("{}/v1/network/chain-status", base_url()?);
let res = test_client()
@@ -29,6 +30,7 @@ async fn test_get_chain_status() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_network_details() -> Result<(), String> {
let url = format!("{}/v1/network/details", base_url()?);
let res = test_client()
@@ -54,6 +56,7 @@ async fn test_get_network_details() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_nym_contracts() -> Result<(), String> {
let url = format!("{}/v1/network/nym-contracts", base_url()?);
let res = test_client()
@@ -75,6 +78,7 @@ async fn test_get_nym_contracts() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_nym_contracts_detailed() -> Result<(), String> {
let url = format!("{}/v1/network/nym-contracts-detailed", base_url()?);
let res = test_client()
+9 -1
View File
@@ -2,6 +2,7 @@ use crate::utils::{base_url, get_any_node_id, make_request, test_client, validat
use time::OffsetDateTime;
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_bonded_nodes() -> Result<(), String> {
let url = format!("{}/v1/nym-nodes/bonded", base_url()?);
let res = make_request(&url).await?;
@@ -19,6 +20,7 @@ async fn test_get_bonded_nodes() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_described_nodes() -> Result<(), String> {
let url = format!("{}/v1/nym-nodes/described", base_url()?);
let res = make_request(&url).await?;
@@ -37,13 +39,14 @@ async fn test_get_described_nodes() -> Result<(), String> {
// TODO enable this once noise is properly integrated
// #[tokio::test]
#[test_with::env(NYM_API)]
// async fn test_get_noise() -> Result<(), String> {
// let url = format!("{}/v1/nym-nodes/noise", base_url()?);
// let res = test_client().get(&url).send().await.map_err(|err| panic!("Failed to send request to {}: {}", url, err))?;
// let json = validate_json_response(res).await;
// }
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_rewarded_set() -> Result<(), String> {
let url = format!("{}/v1/nym-nodes/rewarded-set", base_url()?);
let res = make_request(&url).await?;
@@ -64,6 +67,7 @@ async fn test_get_rewarded_set() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_annotation_for_node() -> Result<(), String> {
let id = get_any_node_id().await?;
let url = format!("{}/v1/nym-nodes/annotation/{}", base_url()?, id);
@@ -81,6 +85,7 @@ async fn test_get_annotation_for_node() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_historical_performance() -> Result<(), String> {
let id = get_any_node_id().await?;
let date = OffsetDateTime::now_utc().date().to_string();
@@ -101,6 +106,7 @@ async fn test_get_historical_performance() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_performance_history() -> Result<(), String> {
let id = get_any_node_id().await?;
let url = format!("{}/v1/nym-nodes/performance-history/{}", base_url()?, id);
@@ -120,6 +126,7 @@ async fn test_get_performance_history() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_performance() -> Result<(), String> {
let id = get_any_node_id().await?;
let url = format!("{}/v1/nym-nodes/performance/{}", base_url()?, id);
@@ -138,6 +145,7 @@ async fn test_get_performance() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_uptime_history() -> Result<(), String> {
let id = get_any_node_id().await?;
let url = format!("{}/v1/nym-nodes/uptime-history/{}", base_url()?, id);
+1
View File
@@ -1,6 +1,7 @@
use crate::utils::{base_url, make_request, validate_json_response};
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_config_score_details() -> Result<(), String> {
let url = format!("{}/v1/status/config-score-details", base_url()?);
let res = make_request(&url).await?;
@@ -1,6 +1,7 @@
use crate::utils::{base_url, make_request, validate_json_response};
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_skimmed_nodes_active() -> Result<(), String> {
let url = format!("{}/v1/unstable/nym-nodes/skimmed/active", base_url()?);
let res = make_request(&url).await?;
@@ -19,6 +20,7 @@ async fn test_get_skimmed_nodes_active() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_skimmed_active_mixnodes() -> Result<(), String> {
let url = format!(
"{}/v1/unstable/nym-nodes/skimmed/mixnodes/active",
@@ -44,6 +46,7 @@ async fn test_get_skimmed_active_mixnodes() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_skimmed_all_mixnodes() -> Result<(), String> {
let url = format!("{}/v1/unstable/nym-nodes/skimmed/mixnodes/all", base_url()?);
let res = make_request(&url).await?;
@@ -66,6 +69,7 @@ async fn test_get_skimmed_all_mixnodes() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_skimmed_active_exit_gateways() -> Result<(), String> {
let url = format!(
"{}/v1/unstable/nym-nodes/skimmed/exit-gateways/active",
@@ -91,6 +95,7 @@ async fn test_get_skimmed_active_exit_gateways() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_skimmed_all_exit_gateways() -> Result<(), String> {
let url = format!(
"{}/v1/unstable/nym-nodes/skimmed/exit-gateways/all",
@@ -116,6 +121,7 @@ async fn test_get_skimmed_all_exit_gateways() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_skimmed_active_entry_gateways() -> Result<(), String> {
let url = format!(
"{}/v1/unstable/nym-nodes/skimmed/entry-gateways/active",
@@ -141,6 +147,7 @@ async fn test_get_skimmed_active_entry_gateways() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_skimmed_all_entry_gateways() -> Result<(), String> {
let url = format!(
"{}/v1/unstable/nym-nodes/skimmed/entry-gateways/all",
@@ -4,6 +4,7 @@ use crate::utils::{
};
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_gateway_unstable_test_results() -> Result<(), String> {
let identity = get_gateway_identity_key().await?;
let url = format!(
@@ -35,6 +36,7 @@ async fn test_get_gateway_unstable_test_results() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_mixnode_unstable_test_results() -> Result<(), String> {
let mix_id = get_mixnode_node_id().await?;
let url = format!(
@@ -66,6 +68,7 @@ async fn test_get_mixnode_unstable_test_results() -> Result<(), String> {
}
#[tokio::test]
#[test_with::env(NYM_API)]
async fn test_get_latest_network_monitor_run_details() -> Result<(), String> {
let url = format!(
"{}/v1/status/network-monitor/unstable/run/latest/details",
+1 -1
View File
@@ -1,4 +1,4 @@
use dotenv::dotenv;
use dotenvy::dotenv;
use reqwest::{Client, Response};
use serde_json::Value;