Problem/Motivation

DrimageSubscriber::onKernelRequest() calls DrimageManager::image(), which extends core ImageStyleDownloadController and calls deliver(). When another request holds the lock image_style_deliver:<style>:<hash>, core throws ServiceUnavailableHttpException. The subscriber does not catch it, so it is logged as an exception and <img> tags never retry: visitors see broken images. Seen on a production site under concurrent requests on cold derivatives.

Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException: Image generation in progress. Try again shortly.

Related: #3546893 (same message, closed as works as designed, no code change), #3587334 (return handling in the subscriber), #3626466 (subscriber priority).

Steps to reproduce

  1. Install Drupal with Dynamic Responsive Image (Drimage) - Improved 1.0.x-dev, PHP and database as per your environment.
  2. Clear the image style derivatives for a Drimage-rendered image.
  3. Request the same cold derivative from concurrent clients, or hold the image_style_deliver:<style>:<hash> lock from another process while requesting it.
  4. Requests that hit the lock throw the uncaught exception above.

Proposed resolution

In DrimageSubscriber::onKernelRequest(), catch ServiceUnavailableHttpException, retry up to 5 times with usleep(500000), and if still locked answer with a plain Response (503, Retry-After: 3, Cache-Control: no-store) instead of an uncaught exception.

A Kernel test, DrimageSubscriberLockTest, covers both paths: lock held for every attempt (plain 503 with the headers) and lock released during the wait (retried to 200). Unpatched, both tests fail with ServiceUnavailableHttpException.

Also checked with real requests on a DDEV site:

  • Lock held about 1.2s: 200 after about 1.6s.
  • Lock held 8s: plain 503 with Retry-After: 3 and Cache-Control: no-store after about 2s.
  • Missing source file: 404, unchanged. Normal request: 200, unchanged.

Remaining tasks

  • ✅ File an issue
  • ✅ Addition/Change/Update/Fix
  • ✅ Testing to ensure no regression
  • ✅ Automated unit/functional testing coverage
  • ➖ Developer Documentation support
  • ➖ User Guide Documentation support
  • ➖ UX/UI designer responsibilities
  • ➖ Accessibility and Readability
  • ❌ Reviewed by a human
  • ❌ Code review by maintainers
  • ❌ Full testing and approval
  • ❌ Credit contributors
  • ❌ Review with the product owner
  • ✅ Update Release Notes
  • ✅ Release

User interface changes

  • N/A

API changes

  • N/A

Data model changes

  • N/A

Release notes snippet

  • N/A
Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

mutasim al-shoura created an issue. See original summary.

josebc’s picture

rajab natshah made their first commit to this issue’s fork.

rajab natshah’s picture

Status: Active » Needs review

@josebc yes, switched to a lock like core. Pushed to MR !46.

  • Other requests for the same image now wait for the lock (up to 2 s) and get the finished image, instead of a 503 error page.
  • The drimage_s3fs subscriber had the same gap and is fixed too.
  • Added Kernel and functional tests, including stress runs. CI is green.

Ready for review.

rajab natshah’s picture

Re-checked MR !46 against core's lock and stress tested it.

  • Method: same lock API as core. Core gives up at once; the MR waits up to 2 s, then serves the image.
  • Stress (about 2,000 requests at once): 1.0.14 had 414 broken responses and 273 logged errors. The MR has none.
  • CI: green, remote and local.

Follow-up for a separate issue: the web server can serve a half-written image, because core writes it in place. 1.0.14 does this too.

rajab natshah’s picture

Issue summary: View changes
Status: Needs review » Fixed
Issue tags: +drimage_improved-1.0.15

✅ Released in drimage_improved-1.0.15

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.