Problem/Motivation

We have designed our own public API that can result in very long DB queries.

We get a lot of hammering from bots and AI agents, which means we end up with a lot of those long DB queries. Because of this, there are logjams on the DB, so we want to be able to return 503 status codes for DB timeouts. These are JSON responses with Retry-After headers, which have both Drupal cacheable metadata and Symphony Response->setCache() information.

We want these 503 responses to be cacheable, because we know that the request will timeout in the database given the current load. If the same uncached request reaches origin again, it will cause another long DB request, and will probably time out, so we should cache the 503 using page_cache. The cache time should be roughly equivalent to the Retry-After value. That is, the Drupal cacheable metadata will include max-age = $retry_after_period.

The caching system does some things that ruin our plans, however, if we want this response cached at origin:

  • The NoServerError response policy disallows caching for any response in the 500-599 range. This is the specific error we’re trying to fix in this issue.
  • Attempting to override the NoServerError service using decorates: page_cache_no_server_error didn’t work, leaving only a patch to core as a solution.
  • page_cache module likes to ignore the Max-Age and instead use -1 (permanent). The workaround of using dynamic_page_cache is OK, but this means page_cache becomes a special case. We don’t want to permanently cache a 503 response by accident, after someone mistakenly enables page_cache. Fixing this is out of scope for this issue, tho might be a nice side-effect.

Steps to reproduce

Try to make a 503 response cacheable.

Proposed resolution

In our patch, we modify NoServerError to carve out a special case for 503s that can be cached. This patch meets our needs, but probably not everyone’s. This should be seen as an illustration of what’s required to solve this kind of problem currently.

Ideally I’d be able to change caching policy without patching core. So I’d be able to substitute a more refined policy for NoServerError as a decorated service, or however it’s implemented.

Some ideas for implementation:

  • Incorporate the patch here and just allow 503s to be cached. :-)
  • Allow targeted overrides of policies (tag for both service collection and override in some way)
  • Add your idea….

There seem to be a zillion other issues around needing flexibility in this area, and I haven’t been able to look at them all. Please add relevant related issues if this has already been solved.

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

CommentFileSizeAuthor
#2 drupal-11x-503-response-policy.patch1.5 KBmile23

Comments

mile23 created an issue. See original summary.

mile23’s picture

StatusFileSize
new1.5 KB

Since this issue is a feature request it's targeted to 12.x, but the patch we're using is 11.x

quietone’s picture

Version: 12.0.x-dev » main

Changing to the development branch, main.

longwave’s picture

Even if decorating doesn't work can't you just swap the class of page_cache_no_server_error? There isn't really anything that requires decoration.

Would also be interesting to know why decoration doesn't work here.

longwave’s picture

mile23’s picture

Since I filed this I had another workaround: Subclass Response to return a different value for isServerError(): https://git.drupalcode.org/project/drupal/-/blob/12.0.x/core/lib/Drupal/...

But that's also a brittle solution.

longwave’s picture

You could also just remove the tags of the core policy service in a service provider, and add your own policy service that does whatever you need.