mirror of
https://github.com/cloudflare/pingora.git
synced 2024-09-20 02:31:35 +02:00
Set stale-updating as an explicit CachePhase
This cache phase indicates when we are serving a stale cache hit, but there is another request currently updating the asset.
This commit is contained in:
parent
9a887b0584
commit
f9ac1082ad
5 changed files with 29 additions and 8 deletions
2
.bleep
2
.bleep
|
@ -1 +1 @@
|
|||
f6e596e897d73c69369ae85edf58cec64b106969
|
||||
a626a70391421eb80e6cdc6c3ceb4d16f38367e8
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")?
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue