Problem/Motivation

Route rebuilds currently happen in a kernel.terminate event subscriber.

Symfony calls fastcgi_finish_request() in Response::send() if that function is available, which means the response is actually sent to the browser. kernel.terminate is then called after Response::send().

When the response is a RedirectResponse this means the next request after a form submission starts processing before the first one has finished.

This in turn means that a single administrator can trigger the race condition described at #2572285: Module enabling and router rebuilding should be done in one transaction, at least if fcgi_finish_request() is available and MySQL is using READ COMMITTED, but possibly not only restricted to that combination.

Proposed resolution

Move it to kernel.finish_request

Remaining tasks

User interface changes

API changes

Data model changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

catch created an issue. See original summary.

damiankloip’s picture

Issue summary: View changes
FileSize
1.46 KB

Adding patch here incase we do want to isolate that fix to here.

Me and catch were going through the code and rather that try to just catch the exception, which could lead to problems discussed above. As well as coding around kind of specifically for a case like this.

We could consider just moving the rebuild event subscriber to use FINISH_REQUEST instead of TERMINATE. As this will always run before the response is sent (See HttpKernel::filterResponse()), terminate is called after the response is sent.

Updated the summary slightly too.

damiankloip’s picture

Status: Active » Needs review
dawehner’s picture

I think we want to listen on both.
A) finish request is the right thing if you deal with an actual HTTP request, I totally agree with that
b) For drush you want to rebuild when drush is done, and afaik we fire the kernel terminate in drush
but not in drush.
So I would propose to add both events + keeping the ifNeeded()

damiankloip’s picture

Yes, that is a fair point. For regular HTTP requests, finish_request will get called, where as drush will only call terminate. So rebuildIfNeeded() will not be needed in terminate for HTTP requests as it's already called from finish_request. So it will just be a NULL op.

damiankloip’s picture

So the options are implement both (meh), or drush also implements the finish_request event also.

dawehner’s picture

Status: Needs review » Needs work

The later one would be wrong though, IMHO

mpdonadio’s picture

Status: Needs work » Needs review
FileSize
1.43 KB

Straight rebase b/c patch wouldn't apply.

mpdonadio’s picture

And a patch that responds to both.

dawehner’s picture

This still doesn't help if the entire service is not registered in the core.services.yml file.

mpdonadio’s picture

Assigned: Unassigned » mpdonadio

Talked w/ @dawehner briefly about this in IRC and will post a more better version tonight.

mpdonadio’s picture

dawehner’s picture

Do we need a test? Is this really testable?

I'm pretty sure we can test this with a kernel test.

damiankloip’s picture

Did you see #2564921: In PHP-FPM environment, enabling a module in using a 'configure' route leads to an error page, as this was originally created based on that. The two containers is a real issue so I don't think we gain anything from doing this yet?

tim.plunkett’s picture

The latest patch does not match the issue title.

dawehner’s picture

Added an issue to at least try to explore the ideas around separating rebuilding in its own step: #2600028: Try to rebuild the container after module install in its own controller

catch’s picture

Title: Do not rebuild router in kernel.terminate » Race condition due to router rebuild in kernel.terminate
Issue tags: -rc target +8.0.1 target
effulgentsia’s picture

Title: Race condition due to router rebuild in kernel.terminate » Race condition triggerable by a single user due to router rebuild in kernel.terminate

Retitling further since moving from TERMINATE to FINISH_REQUEST doesn't fully solve the race condition described in #2572285: Module enabling and router rebuilding should be done in one transaction, only the single-user race condition described in this issue's summary, which is still progress.

anavarre’s picture

Could this be added as a 8.0.2 target?

UniversalAdmin’s picture

Title: Race condition triggerable by a single user due to router rebuild in kernel.terminate » UniversalAdministrator
Assigned: Unassigned »
Category: Bug report » Plan
Issue summary: View changes
Status: Needs review » Active
cilefen’s picture

Title: UniversalAdministrator » Race condition triggerable by a single user due to router rebuild in kernel.terminate
Assigned: » Unassigned
Category: Plan » Bug report
Status: Active » Needs review
cilefen’s picture

Version: 8.0.x-dev » 8.1.x-dev
Issue tags: -8.0.1 target
UniversalAdmin’s picture

Title: Race condition triggerable by a single user due to router rebuild in kernel.terminate » UniversalAdministrator
Version: 8.1.x-dev » 9.x-dev
Assigned: Unassigned »
Category: Bug report » Plan
Issue summary: View changes
Status: Needs review » Active
mpdonadio’s picture

Title: UniversalAdministrator » Race condition triggerable by a single user due to router rebuild in kernel.terminate
Version: 9.x-dev » 8.1.x-dev
Assigned: » Unassigned
Category: Plan » Bug report
Status: Active » Needs review

Please stop changing this. Thanks.

Haza’s picture

Hi

This issue is easy to trigger using the Core Search pages config.

Go to Configuration > Search pages, add a new page, save. You are expected to be redirected on the new search page, instead you get an "unknown route" Fatal error.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

dawehner’s picture

Now that RouterRebuildSubscriber is gone with #2613400: Remove Drupal\Core\EventSubscriber\RouterRebuildSubscriber do we still have this issue actually?

catch’s picture

Haza’s picture

And to answer @dawehner, I'm still able to reproduce this with the lastest 8.3.x