From: Lukas Wagner <l.wagner@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [PATCH datacenter-manager 3/4] api: resources: subscriptions: switch over to api_cache
Date: Wed, 13 May 2026 15:54:56 +0200 [thread overview]
Message-ID: <20260513135457.573414-4-l.wagner@proxmox.com> (raw)
In-Reply-To: <20260513135457.573414-1-l.wagner@proxmox.com>
Instead of storing the subscription state in a module-level HashMap, use
the newly introduced api_cache module to cache the status.
Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
---
Notes:
Changes since the RFC:
- Use new async cache interface
server/src/api/resources.rs | 81 +++++++++++++------------------------
1 file changed, 29 insertions(+), 52 deletions(-)
diff --git a/server/src/api/resources.rs b/server/src/api/resources.rs
index 50315b11..f549c250 100644
--- a/server/src/api/resources.rs
+++ b/server/src/api/resources.rs
@@ -30,9 +30,10 @@ use proxmox_schema::{api, parse_boolean};
use proxmox_sortable_macro::sortable;
use proxmox_subscription::SubscriptionStatus;
use pve_api_types::{ClusterResource, ClusterResourceNetworkType, ClusterResourceType};
+use serde::{Deserialize, Serialize};
use crate::metric_collection::top_entities;
-use crate::{connection, views};
+use crate::{api_cache, connection, views};
pub const ROUTER: Router = Router::new()
.get(&list_subdirs_api_method!(SUBDIRS))
@@ -798,15 +799,11 @@ async fn get_top_entities(
Ok(res)
}
-#[derive(Clone)]
+#[derive(Clone, Serialize, Deserialize)]
struct CachedSubscriptionState {
node_info: HashMap<String, Option<NodeSubscriptionInfo>>,
- timestamp: i64,
}
-static SUBSCRIPTION_CACHE: LazyLock<RwLock<HashMap<String, CachedSubscriptionState>>> =
- LazyLock::new(|| RwLock::new(HashMap::new()));
-
/// Get the subscription state for a given remote.
///
/// If recent enough cached data is available, it is returned
@@ -815,66 +812,46 @@ pub async fn get_subscription_info_for_remote(
remote: &Remote,
max_age: u64,
) -> Result<HashMap<String, Option<NodeSubscriptionInfo>>, Error> {
- if let Some(cached_subscription) = get_cached_subscription_info(&remote.id, max_age) {
+ if let Some(cached_subscription) =
+ get_cached_subscription_info(remote.id.clone(), max_age).await?
+ {
Ok(cached_subscription.node_info)
} else {
let node_info = fetch_remote_subscription_info(remote).await?;
- let now = proxmox_time::epoch_i64();
- update_cached_subscription_info(&remote.id, &node_info, now);
+ update_cached_subscription_info(remote.id.clone(), node_info.clone()).await?;
Ok(node_info)
}
}
-fn get_cached_subscription_info(remote: &str, max_age: u64) -> Option<CachedSubscriptionState> {
- let cache = SUBSCRIPTION_CACHE
- .read()
- .expect("subscription mutex poisoned");
+const SUBSCRIPTION_STATE_CACHE_KEY: &str = "subscription-state";
- if max_age == 0 {
- return None;
- }
- if let Some(cached_subscription) = cache.get(remote) {
- let now = proxmox_time::epoch_i64();
- let diff = now - cached_subscription.timestamp;
-
- if diff >= max_age as i64 || diff < 0 {
- // value is too old or from the future
- None
- } else {
- Some(cached_subscription.clone())
- }
- } else {
- None
- }
+async fn get_cached_subscription_info(
+ remote: String,
+ max_age: u64,
+) -> Result<Option<CachedSubscriptionState>, Error> {
+ let cache = api_cache::read_remote(&remote).await?;
+ Ok(cache
+ .get_with_max_age(SUBSCRIPTION_STATE_CACHE_KEY, max_age as i64)
+ .await?)
}
/// Update cached subscription data.
///
/// If the cache already contains more recent data we don't insert the passed resources.
-fn update_cached_subscription_info(
- remote: &str,
- node_info: &HashMap<String, Option<NodeSubscriptionInfo>>,
- now: i64,
-) {
- // there is no good way to recover from this, so panicking should be fine
- let mut cache = SUBSCRIPTION_CACHE
- .write()
- .expect("subscription mutex poisoned");
+async fn update_cached_subscription_info(
+ remote: String,
+ node_info: HashMap<String, Option<NodeSubscriptionInfo>>,
+) -> Result<(), Error> {
+ let cache = api_cache::write_remote(&remote).await?;
- if let Some(cached_resource) = cache.get(remote) {
- // skip updating if the data is new enough
- if cached_resource.timestamp >= now {
- return;
- }
- }
-
- cache.insert(
- remote.into(),
- CachedSubscriptionState {
- node_info: node_info.clone(),
- timestamp: now,
- },
- );
+ Ok(cache
+ .set(
+ SUBSCRIPTION_STATE_CACHE_KEY,
+ CachedSubscriptionState {
+ node_info: node_info,
+ },
+ )
+ .await?)
}
/// Maps a list of node subscription infos into a single [`RemoteSubscriptionState`]
--
2.47.3
next prev parent reply other threads:[~2026-05-13 13:55 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-13 13:54 [PATCH datacenter-manager 0/4] add generic, per-remote (and global) cache for remote API responses Lukas Wagner
2026-05-13 13:54 ` [PATCH datacenter-manager 1/4] add persistent, generic, namespaced key-value cache implementation Lukas Wagner
2026-05-15 9:06 ` Thomas Lamprecht
2026-05-15 9:19 ` Lukas Wagner
2026-05-13 13:54 ` [PATCH datacenter-manager 2/4] add api_cache as a specialized wrapper around the namespaced cache Lukas Wagner
2026-05-15 9:06 ` Thomas Lamprecht
2026-05-15 9:22 ` Lukas Wagner
2026-05-13 13:54 ` Lukas Wagner [this message]
2026-05-15 9:06 ` [PATCH datacenter-manager 3/4] api: resources: subscriptions: switch over to api_cache Thomas Lamprecht
2026-05-15 9:49 ` Lukas Wagner
2026-05-13 13:54 ` [PATCH datacenter-manager 4/4] remote-updates: switch over to new api_cache Lukas Wagner
2026-05-15 9:06 ` Thomas Lamprecht
2026-05-15 12:56 ` Lukas Wagner
2026-05-15 8:30 ` superseded: [PATCH datacenter-manager 0/4] add generic, per-remote (and global) cache for remote API responses Lukas Wagner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260513135457.573414-4-l.wagner@proxmox.com \
--to=l.wagner@proxmox.com \
--cc=pdm-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.