-
Notifications
You must be signed in to change notification settings - Fork 378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
condfetch: Skip revalidation of an invalidated stale_oc #4082
base: master
Are you sure you want to change the base?
Conversation
cc56c8b
to
9257ac3
Compare
@hermunn brought an interesting point regarding bans. We check the stale object against newer bans during lookup, but in the absence of another lookup or if the ban lurker doesn't get a chance to evaluate post-lookup bans (and the default To get the discussion started I pushed what could look like evaluating bans before and after 304 revalidation. I will turn this pull request into a draft. |
I understand that Dridi prepared these patches in a rush, so once the dust has settled, I would appreciate better explanations in the commit messages. Regarding the actual issue here, I am not convinced yet that failing with a fetch error for the race is the best option (it might be, but I would like to think about it). There will probably be many sites for which the current behavior is just fine, and who would start to see errors unless they added the If someone issues a Again, not sure yet. |
bugwash:
|
a0b6a7e
to
541cd7a
Compare
Updated as per bugwash consensus. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks really good after cleanup.
TBD (missing documentation and coverage)
A valid stale objcore may be selected during lookup, enabling a conditional fetch from the backend. Depending on the backend, or the resource being requested, this may leave a long window during which the stale object may be invalidated. In that case, a 304 response would defeat the invalidation, making it possible for invalidated response header fields or bodies to be perpetuated despite Varnish reporting a successful invalidation. We should consider adding this to vcl_backend_error: if (beresp.was_304) { unset bereq.http.If-Modified-Since; unset bereq.http.If-None-Match; return (retry(fetch)); } This would mostly preserve the current behavior, as observed by a client. In particular, when the ETag of the invalidated stale object is still the same when a new copy is fetched, the client side INM processing would remain. Varnish would simply no longer merge and reuse invalidated stale objects internally. From the point of view of an operator, there would of course be a visible change in the presence of a retry.
When it is time to decide between making a bereq for a regular or conditional fetch, we need to ensure that the stale object is still valid. There is a window between the lookup and the begining of a fetch task during which the object could have been invalidated. The window is in theory much smaller than the one between the lookup and the processing of a 304 response, but it can be significant if the fetch task was queued or restarted. Catching it early allows to proceed with a regular fetch.
Named after vcl_backend_refresh from varnishcache#3994.
@AlveElde brought up an interesting point in an offline discussion. An implicit retry from the built-in VCL is not desirable since there is no guarantee that I added at the beginning of this patch series two commits that:
The This allows an effective retry at the actual step where we initiate the backend request, skipping On the other hand, the original commits from this pull request were updated with their documentation and coverage adjusted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have been thinking about this a lot (I have also looked at the code), and I have some opinions:
- Introducing retries in the default VCL is a change very likely cause confusion and unexpected behavior in setups where users already have some complexity in their backend
sub
s. In particular, anyone writingif (bereq.retries > 0)
might have assumptions baked in about why the retry happens (in their VCL), and they did not think about this other posibility. The fact thatsub vcl_backend_fetch
is not run twice (something we need coverage on, for sure) makes it better, but the fact that you can have abereq.retries > 0
insub vcl_backend_response
after going only once throughsub vcl_backend_fetch
is a gotcha, and needs to be documented carefully. It might be better to have two variables you can check in VCL, one which includes these short false starts, and one which does not. - When a backend responds with 304, it is correct and reasonable to evaluate new bans against the
stale_oc
. Am also convinced that the right Varnish behavior is to refuse to deliver that banned stale object,with no way to override this from VCL.
It is right to drop thestale_oc
reference and go tosub vcl_backend_error
, like this PR does. The conundrum for me, is what Varnish and the default VCL should do when this unfortunate situation, a banned stale OC with nothing to send to the client, happens.
Maybe it is better to insist that the user ask (through VCL in sub vcl_backend_fetch
, or through a parameter) for the immediate retry sans IMS headers without taking a detour through sub vcl_backend_error
. This will make the change to the Varnish Final state less dramatic, but I am not sure about our users' needs in this area.
In other words, we would leave return (retry)
as it is now, allowing users to, if they really need it, do relatively complex logic for this case, while most users simply will opt in or out of the immediate retry. Of course, Varnish would remove the IMS headers at the right moment, probably before going back to sub backend_fetch
, while the default VCL would simply serve a 503.
I agree with the points you raise. I still think that an explicit
Or maybe make this opt-in, without a detour via sub vcl_backend_fetch {
set bereq.retry_dying_304 = true;
} No rug pull, no PRIV_TASK loss, no required attention to |
I think the new VCL variable Also, I see your point with |
I'm wondering to which extent we could actually tie this to See #3994 for more details. That would make the edit: and this could not qualify as a breaking change in a new subroutine for which there is no preexisting VCL. |
If we can catch a dying stale_oc before initiating a condfetch, we can fall back to a regular fetch instead. If we catch it too late, when we are ready to merge headers, we transition to
vcl_backend_error
and get a chance to retry.This avoids a race between a condfetch and the invalidation of its stale objcore, covered with a purge in test cases.