Problem/Motivation
We need to be able to determine when a recipe is being installed. This will help fix locale issues, for example, #3472317: Config language adaptation and translation does not happen at all when config is applied from a recipe as we need to make the locale system react to recipe install and also contrib projects like Canvas which are doing exceptionally complex changes to configuration when a theme installed.
Proposed resolution
Add an enum that can differentiate between a recipe install and config sync but do not break BC for any of the isSyncing API. The recipe system uses the syncing flag to be able to take config install during extension install and make the module and theme installer use its configuration and not the extensions.
The isSyncing api includes:
- \Drupal\Core\Config\ConfigInstallerInterface::isSyncing()
- \Drupal::isConfigSyncing()
- \Drupal\Core\Entity\SynchronizableInterface::isSyncing()
Remaining tasks
User interface changes
None
Introduced terminology
N/a
API changes
TBD
Data model changes
None
Release notes snippet
TBD
Issue fork drupal-3613607
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
Comment #2
alexpottAfter writing the issue I began to wonder if we're going to cause ourselves more problems by mixing config syncing and recipe installing. They definitely are related in the way that the recipe system uses the config sync - but perhaps this should just be something new and separate.
Comment #3
penyaskitoI never created an issue about this, but have been questioning this in Slack for a very long time.
A common problem we've faced and this would solve: in a config
preSave()we "heal" some configuration entity, e.g. after adding a new config schema prop.For an existing site, an upgrade/post_update would run on dev/staging, and will be deployed to prod. That means we want to gate this on
isSyncing(), so it doesn't run on a staging → prod deployment.But if a module is providing shipped config, we want to heal that on installation. We can do that on
preSave().But what about recipes? Currently, that has
isSyncing(), so there's no way to discern both. And as we cannot know which version was used for creating a config that is part of a recipe, we can't really attempt to self-heal recipes' provided config.This is a problem in the context of Drupal CMS / Site templates, specially in combination with Drupal Canvas.
Comment #4
wim leers@penyaskito cross-posted with me!
Another impact: update paths. If config entity types need update paths and they follow the best practices in #3521618: Add generic interface + base class for upgrade paths that require config changes, then the
preSave()-triggered update paths in there:Currently both trigger
isSyncing() === TRUE.Further complication: Recipes installation is sometimes syncing, sometimes not
The syncing flag's value during recipe application appears to depend on which part of recipe installation/application is happening! Quoting a snippet of Canvas code (which I do not know nor claim to be fully accurate, but I'm hoping it might be a helpful bit of information in pushing this issue forward):
Comment #5
phenaproximaIdeally, core would have an actual API to determine if a recipe is being applied. That is being added over in #3613607: Add RecipeRunner::isApplying() to determine if a recipe is being applied, without confusing it with a config sync.
But until that's there, could Canvas broaden its check by looking for
RecipeRunneranywhere in the backtrace, regardless of which method is being called? The presence of that class is a clear-as-a-bell indicator that a recipe is being applied.Comment #6
wim leersChanging
to instead check a class being present seems fine to me 🤓 As long as it contains
!
Comment #7
phenaproximaOh, hah, look at that: I related the issue to itself.
Comment #8
wim leersFYI, @phenaproxima tried leaping ahead of this landing in https://git.drupalcode.org/project/canvas/-/work_items/3591985
Comment #9
wim leersComment #10
phenaproximaWe need a new method to determine if a recipe is being applied:
RecipeRunner::isApplying().We can still use config sync -- not sure we can really undo that now -- but at least this will allow us to cleanly separate the concepts.
Comment #12
phenaproximaDiscussed with @alexpott over Zoom.
I'm of the opinion that a totally separate flag is the right thing to do here. Although recipes have config sync-like behavior at certain points, they are not a config sync, and in the real world you are never actually syncing config while applying a recipe.
In other words, our API is describing a bogus situation, and developers are left holding the bag because they need to awkwardly account for that. For example, the $is_syncing flag in
hook_modules_installed()is a damned lie when it is TRUE during recipe application. A module is being installed, but you're not really syncing!We agreed that the path forward here is:
RecipeRunner::isApplying()in this issue as an immediate escape hatch for modules like Canvas, which currently have to implement torturous workarounds for recipes.Comment #13
alexpottComment #14
phenaproximaIMHO, ship it. The test proves that every step that could be called by a batch job is covered by the flag. The implementation is simple and I like it.
Comment #15
phenaproximaComment #16
phenaproximaComment #17
quietone commentedTrying for a concise title for the git commit message.
Comment #18
alexpottI've added a CR as we're adding a new method that people should know about but also changed this to a bug fix as shown by the missing config hash when a recipe is installed.
Comment #19
alexpott@gábor hojtsy reviewed this code as part of #3337864: Ensure "Site default language' is used when installing config by any means and is updated correctly and made a change based on his feedback.
Comment #22
catchHad one nit on the naming, but I see Gabor already also pointed out a similar thing and improved it to its current state. I don't have an improvement so let's leave it how it is - private method so could always be changed later.
After committing I realised the issue summary still mentions an enum, this could use an update for anyone who lands on this issue.
Apart from that I can't see anything to complain about. It might be good if the change record mentioned the use cases in #3 and #4 though since the example in there is a bit arbitrary.
Committed/pushed to main and 11.x, thanks!
Comment #24
phenaproximaPer #18, this is a bug fix and should ideally be backported to 11.4.x.
I'd also agree it's a bug because the status quo, where config sync is confused with recipe application, causes problems. This isn't the full fix to that problem, but it's an important step in the right direction, and it enables other related, and very important, bugs to be fixed.
Changing status accordingly.
Comment #25
alexpottFor more info on #18 - config that doesn't have the config hash is not translated by locale so modules installed via recipes don't get their configuration translated.
Comment #27
alexpottI've created a backport branch so we can see if tests are passing.
Comment #28
godotislateDiscussed with @catch on Slack, and I think I'm OK with an 11.4.x backport. There is a new method on
RecipeRunner, but the class is final and can't be extended, so I think it's fine.Comment #29
catchI had not thought about the class being final, only the new method, so yes this seems fine for backport, was on the fence otherwise.
Comment #30
smustgrave commentedSeems like a good backport for 11.4.x
Going through the patch to be ported issues.
Comment #31
catchCommitted/pushed to 11.4.x, thanks!