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
Comment | File | Size | Author |
---|---|---|---|
#12 | interdiff-09-12.txt | 608 bytes | mpdonadio |
#12 | do_not_rebuild_router-2572293-12.patch | 2.22 KB | mpdonadio |
#9 | interdiff-08-09.txt | 1.54 KB | mpdonadio |
#9 | do_not_rebuild_router-2572293-9.patch | 1.62 KB | mpdonadio |
#8 | do_not_rebuild_router-2572293-8.patch | 1.43 KB | mpdonadio |
Comments
Comment #2
damiankloip CreditAttribution: damiankloip commentedAdding patch here incase we do want to isolate that fix to here.
Updated the summary slightly too.
Comment #3
damiankloip CreditAttribution: damiankloip commentedComment #4
dawehnerI 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()
Comment #5
damiankloip CreditAttribution: damiankloip commentedYes, 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.
Comment #6
damiankloip CreditAttribution: damiankloip commentedSo the options are implement both (meh), or drush also implements the finish_request event also.
Comment #7
dawehnerThe later one would be wrong though, IMHO
Comment #8
mpdonadioStraight rebase b/c patch wouldn't apply.
Comment #9
mpdonadioAnd a patch that responds to both.
Comment #10
dawehnerThis still doesn't help if the entire service is not registered in the
core.services.yml
file.Comment #11
mpdonadioTalked w/ @dawehner briefly about this in IRC and will post a more better version tonight.
Comment #12
mpdonadioOk, service is back.
#2164367: Rebuild router as few times as possible per request added it.
#356399: Optimize the route rebuilding process to rebuild on write removed it.
Do we need a test? Is this really testable?
Comment #13
dawehnerI'm pretty sure we can test this with a kernel test.
Comment #14
damiankloip CreditAttribution: damiankloip commentedDid 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?
Comment #15
tim.plunkettThe latest patch does not match the issue title.
Comment #16
dawehnerAdded 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
Comment #17
catchComment #18
effulgentsia CreditAttribution: effulgentsia at Acquia commentedRetitling 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.
Comment #19
anavarreCould this be added as a 8.0.2 target?
Comment #20
UniversalAdmin CreditAttribution: UniversalAdmin as a volunteer and commentedComment #21
cilefen CreditAttribution: cilefen commentedComment #22
cilefen CreditAttribution: cilefen commentedComment #23
UniversalAdmin CreditAttribution: UniversalAdmin as a volunteer and commentedComment #24
mpdonadioPlease stop changing this. Thanks.
Comment #25
HazaHi
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.
Comment #27
dawehnerNow that RouterRebuildSubscriber is gone with #2613400: Remove Drupal\Core\EventSubscriber\RouterRebuildSubscriber do we still have this issue actually?
Comment #28
catchI think it's a duplicate of #2572285: Module enabling and router rebuilding should be done in one transaction now.
Comment #29
HazaAnd to answer @dawehner, I'm still able to reproduce this with the lastest 8.3.x