diff options
-rw-r--r-- | .bleep | 2 | ||||
-rw-r--r-- | pingora-cache/src/lib.rs | 19 | ||||
-rw-r--r-- | pingora-proxy/src/proxy_cache.rs | 5 | ||||
-rw-r--r-- | pingora-proxy/tests/test_upstream.rs | 8 | ||||
-rw-r--r-- | pingora-proxy/tests/utils/server_utils.rs | 3 |
5 files changed, 29 insertions, 8 deletions
@@ -1 +1 @@ -f6e596e897d73c69369ae85edf58cec64b106969
\ No newline at end of file +a626a70391421eb80e6cdc6c3ceb4d16f38367e8
\ No newline at end of file diff --git a/pingora-cache/src/lib.rs b/pingora-cache/src/lib.rs index a999f7e..d1346e5 100644 --- a/pingora-cache/src/lib.rs +++ b/pingora-cache/src/lib.rs @@ -77,6 +77,8 @@ pub enum CachePhase { Miss, /// A staled (expired) asset is found Stale, + /// A staled (expired) asset was found, but another request is revalidating it + StaleUpdating, /// A staled (expired) asset was found, so a fresh one was fetched Expired, /// A staled (expired) asset was found, and it was revalidated to be fresh @@ -96,6 +98,7 @@ impl CachePhase { CachePhase::Hit => "hit", CachePhase::Miss => "miss", CachePhase::Stale => "stale", + CachePhase::StaleUpdating => "stale-updating", CachePhase::Expired => "expired", CachePhase::Revalidated => "revalidated", CachePhase::RevalidatedNoCache(_) => "revalidated-nocache", @@ -260,7 +263,7 @@ impl HttpCache { use CachePhase::*; match self.phase { Disabled(_) | Bypass | Miss | Expired | Revalidated | RevalidatedNoCache(_) => true, - Hit | Stale => false, + Hit | Stale | StaleUpdating => false, Uninit | CacheKey => false, // invalid states for this call, treat them as false to keep it simple } } @@ -509,6 +512,7 @@ impl HttpCache { match self.phase { CachePhase::Hit | CachePhase::Stale + | CachePhase::StaleUpdating | CachePhase::Revalidated | CachePhase::RevalidatedNoCache(_) => self.inner_mut().body_reader.as_mut().unwrap(), _ => panic!("wrong phase {:?}", self.phase), @@ -544,6 +548,7 @@ impl HttpCache { | CachePhase::Miss | CachePhase::Expired | CachePhase::Stale + | CachePhase::StaleUpdating | CachePhase::Revalidated | CachePhase::RevalidatedNoCache(_) => { let inner = self.inner_mut(); @@ -786,6 +791,14 @@ impl HttpCache { // TODO: remove this asset from cache once finished? } + /// Mark this asset as stale, but being updated separately from this request. + pub fn set_stale_updating(&mut self) { + match self.phase { + CachePhase::Stale => self.phase = CachePhase::StaleUpdating, + _ => panic!("wrong phase {:?}", self.phase), + } + } + /// Update the variance of the [CacheMeta]. /// /// Note that this process may change the lookup `key`, and eventually (when the asset is @@ -854,6 +867,7 @@ impl HttpCache { match self.phase { // TODO: allow in Bypass phase? CachePhase::Stale + | CachePhase::StaleUpdating | CachePhase::Expired | CachePhase::Hit | CachePhase::Revalidated @@ -882,6 +896,7 @@ impl HttpCache { match self.phase { CachePhase::Miss | CachePhase::Stale + | CachePhase::StaleUpdating | CachePhase::Expired | CachePhase::Hit | CachePhase::Revalidated @@ -1006,7 +1021,7 @@ impl HttpCache { /// Whether this request's cache hit is staled fn has_staled_asset(&self) -> bool { - self.phase == CachePhase::Stale + matches!(self.phase, CachePhase::Stale | CachePhase::StaleUpdating) } /// Whether this asset is staled and stale if error is allowed diff --git a/pingora-proxy/src/proxy_cache.rs b/pingora-proxy/src/proxy_cache.rs index 5e90b18..77b7384 100644 --- a/pingora-proxy/src/proxy_cache.rs +++ b/pingora-proxy/src/proxy_cache.rs @@ -165,7 +165,9 @@ impl<SV> HttpProxy<SV> { } else { break None; } - } // else continue to serve stale + } + // else continue to serve stale + session.cache.set_stale_updating(); } else if session.cache.is_cache_lock_writer() { // stale while revalidate logic for the writer let will_serve_stale = session.cache.can_serve_stale_updating() @@ -182,6 +184,7 @@ impl<SV> HttpProxy<SV> { new_app.process_subrequest(subrequest, sub_req_ctx).await; }); // continue to serve stale for this request + session.cache.set_stale_updating(); } else { // return to fetch from upstream break None; diff --git a/pingora-proxy/tests/test_upstream.rs b/pingora-proxy/tests/test_upstream.rs index 2600832..c2499f5 100644 --- a/pingora-proxy/tests/test_upstream.rs +++ b/pingora-proxy/tests/test_upstream.rs @@ -1373,7 +1373,7 @@ mod test_cache { .unwrap(); assert_eq!(res.status(), StatusCode::OK); let headers = res.headers(); - assert_eq!(headers["x-cache-status"], "stale"); + assert_eq!(headers["x-cache-status"], "stale-updating"); assert_eq!(res.text().await.unwrap(), "hello world"); }); // sleep just a little to make sure the req above gets the cache lock @@ -1387,7 +1387,7 @@ mod test_cache { .unwrap(); assert_eq!(res.status(), StatusCode::OK); let headers = res.headers(); - assert_eq!(headers["x-cache-status"], "stale"); + assert_eq!(headers["x-cache-status"], "stale-updating"); assert_eq!(res.text().await.unwrap(), "hello world"); }); let task3 = tokio::spawn(async move { @@ -1399,7 +1399,7 @@ mod test_cache { .unwrap(); assert_eq!(res.status(), StatusCode::OK); let headers = res.headers(); - assert_eq!(headers["x-cache-status"], "stale"); + assert_eq!(headers["x-cache-status"], "stale-updating"); assert_eq!(res.text().await.unwrap(), "hello world"); }); @@ -1436,7 +1436,7 @@ mod test_cache { .unwrap(); assert_eq!(res.status(), StatusCode::OK); let headers = res.headers(); - assert_eq!(headers["x-cache-status"], "stale"); + assert_eq!(headers["x-cache-status"], "stale-updating"); assert_eq!(res.text().await.unwrap(), "hello world"); // wait for the background request to finish diff --git a/pingora-proxy/tests/utils/server_utils.rs b/pingora-proxy/tests/utils/server_utils.rs index ec1a962..4f03f21 100644 --- a/pingora-proxy/tests/utils/server_utils.rs +++ b/pingora-proxy/tests/utils/server_utils.rs @@ -473,6 +473,9 @@ impl ProxyHttp for ExampleProxyCache { CachePhase::Hit => upstream_response.insert_header("x-cache-status", "hit")?, CachePhase::Miss => upstream_response.insert_header("x-cache-status", "miss")?, CachePhase::Stale => upstream_response.insert_header("x-cache-status", "stale")?, + CachePhase::StaleUpdating => { + upstream_response.insert_header("x-cache-status", "stale-updating")? + } CachePhase::Expired => { upstream_response.insert_header("x-cache-status", "expired")? } |