Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
While trying to move the task contrib module #2351313: Rerolling to latest core version to latest head there is little to search for when running
$ drush @drupal.d8 cache-rebuild
Recursive router rebuild detected.
The error is gone after
$ drush @drupal.d8 pm-uninstall rest
The following extensions will be uninstalled: rest, hal, restui
Do you really want to continue? (y/n): y
hal was uninstalled successfully. [ok]
rest was uninstalled successfully. [ok]
restui was uninstalled successfully.
Is this because ResourceRoutes::alterRoutes is in err?
For the code see https://github.com/clemens-tolboom/task/tree/feature/2351313-reroll
Proposed resolution
Remaining tasks
User interface changes
API changes
Comment | File | Size | Author |
---|---|---|---|
#26 | 2351253-26-rest-entity-routes-plugins.patch | 7.76 KB | jhedstrom |
Comments
Comment #1
clemens.tolboomComment #2
clemens.tolboomInstalling mentioned module (using the github branch) next enable rest.module give
git hash 5a85df4c194fed184b900f6b0d610b39c6fcdf08
Next exception build in #2230091: Route rebuilding is not guaranteed to finish in time for the next request triggers.
Is module enable (exhausting memory) or the new exception the cause?
Comment #3
BerdirYou need to figure out what is causing the recursion and then we need to fix it. Might be rest.module.
drush doesn't show backtrace, so add a debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) call above the place where the exception is thrown.
Could be the way it is called in EntityDerivate in rest.module:
If $collection is returned, it should never try to call getRouteByName(), so the second part there should move in an inner if.
Comment #4
clemens.tolboomcore/modules/rest/src/Plugin/Derivative/EntityDerivative.php has a @TODO refering to #2158571: Routes added in RouteSubscribers cannot be altered
gives
Fatal error: Call to a member function getPath() on a non-object
Attached patch raises exception on missing $route_name which is unfortunately not logged somewhere.
Comment #5
clemens.tolboomAdded DX tag as the missing route should appear in the http://drupal.d8/admin/reports/dblog
Comment #6
BerdirI think instead of this, we should just repeat the logic inside the catch block and continue. Throwing and immediately catching the exception again is just unecessary overhead.
Comment #7
clemens.tolboom@Berdir I'm not sure what you mean. "repeat the logic" is not DRY. Throwing an exception is way more explicit.
Comment #8
dawehnerBeside the comment from berdir, in general at least let's add a message which is partly helpful.
Comment #9
clemens.tolboomTrouble the message will end nowhere. What about adding a logger
Question remaining is : # what is different with the throw done above and the more general one?
Comment #10
BerdirDRY is a nice principle, but not using exceptions for code flow is as well. And we're talking about two lines here.
If you want DRY, then move those two lines within the catch below it and check for if (!isset($route)).
Comment #11
clemens.tolboom@Berdir please add your patch otherwise we're playing ping pong.
A misconfiguration of a route name is IMHO an exception of which the DX should be notified. Thus this needs a log message.
Comment #12
BerdirBut it is not a misconfiguration, it is a known issue with the current routing/entity links systems and is being addressed in #2259445: Entity Resource unification.
This is what I was suggesting. Also had to harden ResourceRoutes in case you have default configuration for entity types during installation which are currently not there because the derivative class (which should be named Deriver) skipped them.
Comment #13
larowlanI assume no way we can add a test here? Unless rebuild.php can be used?
Comment #14
jhedstromYou can always test :)
Comment #18
jhedstromReroll of #14. I've re-included the test-only patch to illustrate the fix.
Comment #20
jhedstromComment #21
klausiLooks almost ready!
the assertion messages are confusing. I think the "not" is wrong. The assertion message should tell you what should happen. If it does not happen during the test then the assertion message will be red, so you don't specify the fail message here but the success message.
Comment #22
jhedstromThat is the case with SimpleTests, but with PHPUnit, my understanding was that we use a message to describe the failure since that is the only time it is displayed. I'm not finding this documented for Drupal though. Looking through our existing tests, I'm seeing that to be the case (see
\Drupal\Tests\Core\Site\SettingsTest
for instance).Comment #23
klausiInteresting, so this should not be blocked on the assertion messages.
If you look at https://phpunit.de/manual/current/en/appendixes.assertions.html#appendix... PHPUnit has very useful output in the generic assertion messages by printing the actual values, which is very helpful when looking at broken tests. Maybe we should move the message to a code comment and stick with the default assertion?
I noticed that there is no test coverage for the RouteNotFound exception in getDerivativeDefinitions(), correct?
Comment #24
jhedstromThe RouteNotFound exception is tested in the last assert, it just isn't testing for a thrown exception (since the exception is caught).
Comment #25
jhedstromI could reroll to remove the custom assert messages--most core tests seem to not use custom messages.
Comment #26
jhedstromThis moves the custom assert messages to code comments. I'm not re-attaching the failing test.
Comment #31
tim.plunkettYou can remove a set of parens
Newline, please.
Not "enabling/disabling" anymore.
Can this method be chopped up to test different parts of the code flow, please?
Comment #32
dawehnerIt would be great to understand how this could happen, so we could check that as well, like with some kind of flag somewhere?
Comment #33
Berdir[#2382937] just landed, which is supposed to make this a lot less fragile.
We probably need to re-evaluate if we still need anything added here, but it is probably a good idea to still add the test scenario that resulted in this problem.
@dawehner: I had that too I believe in my project, it happens when the entity type is skipped in the deriver and try to access it (in my case, it was default configuration that triggered that).
Comment #34
BerdirCorrrection. After #2406439: Cleanup EntityDerivative and RouteBuilderInterface.
Comment #35
dawehnerWhen I debugged that some days ago the problem was the following:
Rest module ships with some
rest.settings.yml
which causes a$entity_manager->getDefinition()
callswhich throws an exception during route rebuild time.
Due to our "excellent" idea to render exception pages via our normal rendering system, we get another router rebuild, boom.
Comment #36
dawehnerAfter #356399: Optimize the route rebuilding process to rebuild on write the chance of this happening is much lower, it just can happen if some code actually rebuilds the router on purpose, which most probably won't happen.
Comment #37
Wim LeersThis is the key portion of this patch.
Which means it's solved by #2397271: REST configuration fails if it contains a plugin reference that does not exist, which itself is a temporary measure until #2308745: Remove rest.settings.yml, use rest_resource config entities is solved.