Imagine there's an origin with a chain of caches in front of it, and the caches' clocks are known to be well-synchronized with the origin's clock — perhaps because the caches and the origin are run by the same organization. In that case, the caches could compute a much more accurate Age value by not using the formulas in RFC 9111. However, in order to do so, they would have to exploit this knowledge about their clocks being synchronized, and the RFC doesn't seem to allow them to do that. So, I think giving caches a bit latitude for these cases, so they can compute a more accurate Agewhile remaining spec-compliant, would be nice.
Here's an example scenario to motivate this:
The network path is User Agent -> Cache A -> Cache B -> Cache C -> Origin.
The network latency is 50ms between each hop (100ms round-trip)
When the origin receives a GET /something-expensive request, it forms its response by reading a bunch of data and doing heavy computations on that data; this whole process takes 5 seconds. In order to ensure that the data isn't changing during the course of the computation, the origin takes a snapshot of the data at the beginning of the request, and reads from that snapshot throughout. Because the state of the HTTP resource is a function of this underlying data, the origin's response reflects the state of the resource at the time of the snapshot, so it uses the time of the snapshot as the response Date.
Now, assume the user agent requests GET /something-expensive and there's a cache miss at each cache, so the request gets forwarded all the way to the origin. When the origin receives the request from Cache C, it responds 5 seconds later. When that response reaches Cache C, it won't have an Age header, but Cache C will have observed a 5.1s response_delay (accounting for the 100ms round-trip time between Cache C and the origin). So, using the current_age formula, Cache C will return Age: 5. Then, Cache B sees an age_value of 5 from Cache C's response but it also measures a response_delay of 5.2s. So, the Age value it sends in its response to Cache A is 10s. Finally, Cache A repeats this process and concludes that the response is 15s old, which it returns to the user agent in the Age. In reality, the response is only ~5.15s old at this point, not 15s!
There's a mix here of "double counting" and counting some things that shouldn't be part of the age at all (e.g., the inbound latency from Cache A to the origin). But I think these are well-known limitations to using a response_delay-based age — and they're unavoidable if the servers can't trust each other's clocks.
The point of this issue, though, is about giving the cache more flexibility when the origin's clock is known to be reasonably synchronized with the cache's. In those cases, just using apparent_age will give better results. Right now, though, apparent_age can only be used to increase the computed current_age, via the formula:
If some conditions hold — and I'm not sure exactly how to formalize all the conditions where this would apply — it seems like caches ought to be able to use the apparent_age as the corrected_initial_age, or at least heavily bias the corrected_initial_age toward the apparent_age.
Imagine there's an origin with a chain of caches in front of it, and the caches' clocks are known to be well-synchronized with the origin's clock — perhaps because the caches and the origin are run by the same organization. In that case, the caches could compute a much more accurate
Age
value by not using the formulas in RFC 9111. However, in order to do so, they would have to exploit this knowledge about their clocks being synchronized, and the RFC doesn't seem to allow them to do that. So, I think giving caches a bit latitude for these cases, so they can compute a more accurateAge
while remaining spec-compliant, would be nice.Here's an example scenario to motivate this:
GET /something-expensive
request, it forms its response by reading a bunch of data and doing heavy computations on that data; this whole process takes 5 seconds. In order to ensure that the data isn't changing during the course of the computation, the origin takes a snapshot of the data at the beginning of the request, and reads from that snapshot throughout. Because the state of the HTTP resource is a function of this underlying data, the origin's response reflects the state of the resource at the time of the snapshot, so it uses the time of the snapshot as the responseDate
.Now, assume the user agent requests
GET /something-expensive
and there's a cache miss at each cache, so the request gets forwarded all the way to the origin. When the origin receives the request from Cache C, it responds 5 seconds later. When that response reaches Cache C, it won't have anAge
header, but Cache C will have observed a 5.1sresponse_delay
(accounting for the 100ms round-trip time between Cache C and the origin). So, using thecurrent_age
formula, Cache C will returnAge: 5
. Then, Cache B sees anage_value
of 5 from Cache C's response but it also measures aresponse_delay
of 5.2s. So, theAge
value it sends in its response to Cache A is 10s. Finally, Cache A repeats this process and concludes that the response is 15s old, which it returns to the user agent in theAge
. In reality, the response is only ~5.15s old at this point, not 15s!There's a mix here of "double counting" and counting some things that shouldn't be part of the age at all (e.g., the inbound latency from Cache A to the origin). But I think these are well-known limitations to using a
response_delay
-based age — and they're unavoidable if the servers can't trust each other's clocks.The point of this issue, though, is about giving the cache more flexibility when the origin's clock is known to be reasonably synchronized with the cache's. In those cases, just using
apparent_age
will give better results. Right now, though,apparent_age
can only be used to increase the computedcurrent_age
, via the formula:If some conditions hold — and I'm not sure exactly how to formalize all the conditions where this would apply — it seems like caches ought to be able to use the
apparent_age
as thecorrected_initial_age
, or at least heavily bias thecorrected_initial_age
toward theapparent_age
.