Problem/Motivation
We're seeing some strange "looping" behaviour during installation of a module with enforced config, where the config import process seems to happen several times over, periodically emitting a warning:
[warning] Another request may be synchronizing configuration already.
This appears to be happening at the beginning or end of a "loop"- each cycle ends with a line like:
[notice] Synchronized configuration: update eck.eck_entity_type.publication_widgets.
And begins a new loop like:
[info] Enforced config system.site has changed: importing.
[info] Enforced config system.theme has changed: importing.
[info] Enforced config block.block.views_block__publication_header_block_1 has changed: importing.
[notice] Synchronized configuration: update block.block.views_block__publication_header_block_1.
[notice] Finalizing configuration synchronization.
[notice] The configuration was imported successfully.
It appears the trigger for this behaviour is from ECK, which explicitly calls for a rebuild of caches anytime it saves a bundle for one of its entities. This in turn causes Config Enforce to start a rebuild within the first one, and creates a loop.
This eventually fails like so:
[notice] Synchronized configuration: create eck.eck_type.publication_widgets.template_publication_part_3.
[error] The field_part_a entity reference field (entity_type: publication_widgets, bundle: template_publication_part_3) no longer has any valid bundle it can reference. The
field is not working correctly anymore and has to be adjusted.
[error] Error: Call to undefined method Drupal\config_enforce\EnforcedConfigRegistry::deleteEnforcedConfigs() in Drupal\config_enforce_devel\EnforcedConfigCollection->delet
eEnforcedConfigs() (line 132 of /var/www/html/web/modules/contrib/config_enforce_devel/src/EnforcedConfigCollection.php) #0 /var/www/html/web/modules/contrib/config_enforce_d
evel/src/EventSubscriber/ConfigDeleteSubscriber.php(56): Drupal\config_enforce_devel\EnforcedConfigCollection->deleteEnforcedConfigs(Array)
#1 [internal function]: Drupal\config_enforce_devel\EventSubscriber\ConfigDeleteSubscriber->onConfigDelete(Object(Drupal\Core\Config\ConfigCrudEvent), 'config.delete', Object
(Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher))
#2 /var/www/html/web/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(142): call_user_func(Array, Object(Drupal\Core\Config\ConfigCrudEvent), 'conf
ig.delete', Object(Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher))
#3 /var/www/html/web/core/lib/Drupal/Core/Config/Config.php(246): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object(Drupal\Core\Config\ConfigCru
dEvent), 'config.delete')
#4 /var/www/html/web/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php(228): Drupal\Core\Config\Config->delete()
#5 /var/www/html/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php(490): Drupal\Core\Config\Entity\ConfigEntityStorage->doDelete(Array)
#6 /var/www/html/web/core/lib/Drupal/Core/Entity/EntityBase.php(347): Drupal\Core\Entity\EntityStorageBase->delete(Array)
#7 /var/www/html/web/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php(567): Drupal\Core\Entity\EntityBase->delete()
#8 /var/www/html/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php(484): Drupal\Core\Config\Entity\ConfigEntityBase::preDelete(Object(Drupal\Core\Config\Entity\ConfigEnti
tyStorage), Array)
#9 /var/www/html/web/core/lib/Drupal/Core/Entity/EntityBase.php(347): Drupal\Core\Entity\EntityStorageBase->delete(Array)
#10 /var/www/html/web/core/lib/Drupal/Core/Config/ConfigImporter.php(924): Drupal\Core\Entity\EntityBase->delete()
#11 /var/www/html/web/core/lib/Drupal/Core/Config/ConfigImporter.php(636): Drupal\Core\Config\ConfigImporter->checkOp('', 'create', 'eck.eck_type.pu...')
#12 /var/www/html/web/core/lib/Drupal/Core/Config/ConfigImporter.php(541): Drupal\Core\Config\ConfigImporter->processConfigurations(Array)
#13 /var/www/html/web/modules/contrib/config_enforce/src/ConfigImporter.php(90): Drupal\Core\Config\ConfigImporter->doSyncStep('processConfigur...', Array)
#14 /var/www/html/web/modules/contrib/config_enforce/src/ConfigImporter.php(48): Drupal\config_enforce\ConfigImporter->doImport(Object(Drupal\Core\Config\StorageComparer))
#15 /var/www/html/web/modules/contrib/config_enforce/src/ConfigEnforcer.php(80): Drupal\config_enforce\ConfigImporter->importConfig(Array)
#16 /var/www/html/web/modules/contrib/config_enforce/config_enforce.module(44): Drupal\config_enforce\ConfigEnforcer->enforceConfigs()
#17 [internal function]: config_enforce_rebuild()
#18 /var/www/html/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(426): call_user_func_array(Object(Closure), Array)
#19 /var/www/html/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(405): Drupal\Core\Extension\ModuleHandler->Drupal\Core\Extension\{closure}(Object(Closure), 'config_enf
orce')
#20 /var/www/html/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(433): Drupal\Core\Extension\ModuleHandler->invokeAllWith('rebuild', Object(Closure))
#21 /var/www/html/web/core/includes/common.inc(579): Drupal\Core\Extension\ModuleHandler->invokeAll('rebuild')
#22 /var/www/html/web/modules/contrib/eck/src/Entity/EckEntityBundle.php(110): drupal_flush_all_caches()
#23 /var/www/html/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php(597): Drupal\eck\Entity\EckEntityBundle->postSave(Object(Drupal\Core\Config\Entity\ConfigEntityStorage), false)
#24 /var/www/html/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php(523): Drupal\Core\Entity\EntityStorageBase->doPostSave(Object(Drupal\eck\Entity\EckEntityBundle), false)
#25 /var/www/html/web/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php(253): Drupal\Core\Entity\EntityStorageBase->save(Object(Drupal\eck\Entity\EckEntityBundle))
Steps to reproduce
- Enforce an ECK type and 2 bundles (A and B)
- Create an entityreference field on bundle A that references bundle B
- Store the type and bundle A config in config/install
- Store the bundle B config in config/optional
- Reinstall the module
Proposed resolution
Avoid rebuilding configs if we are already in the process of importing.
Remaining tasks
Write some tests (we have a working patch to fix the behaviour)