Problem/Motivation
Drupal core has a hook_update_N() mechanism with which developers can fix the database. But often we also want to abuse it to deploy other changes. This can lead to the situation that we would like to import the configuration before running the update hooks. But this is a very bad idea and will not be possible in the future.
See #2762235: Ensure that ConfigImport is taking place without outstanding updates and #2628144: Ensure that ConfigImport is taking place against the same code base.
The use case for this is for example adding a new field and dynamically populating it during a particular deployment.
Proposed resolution
Add a hook_post_config_import_NAME called after a config import so that developers can easily write one-off hooks for deployments and still always run the update hooks before the config import.
There is the new HOOK_deploy_NAME which the drush deploy command invokes.
See also the Drush 10 documentation for deploy command
Remaining tasks
Port https://github.com/bircher/drupal-config_import_n to core and pass the import event to the hook.Update documentation (i.e. hook_install(), https://www.drupal.org/docs/8/creating-custom-modules/include-default-co... , etc.) to let developers know this hook is the right place for CRUD operations relying on the default configuration shipped with their modules.
User interface changes
none
API changes
new hooks.
Data model changes
none
| Comment | File | Size | Author |
|---|---|---|---|
| #86 | 2901418-86.patch | 19.1 KB | andypost |
| #86 | interdiff.txt | 13.03 KB | andypost |
| #82 | 2901418-82.patch | 19.95 KB | catch |
Comments
Comment #2
bircherComment #3
gambry#2906107: hook_install() is invoked before the module's default config is installed during config import was a documentation task to let developers know what the best place for CRUD operations against their modules' shipped default configuration is.
D7 users were used to write this in hook_install() and hook_updates(). In D8 this is not possible anymore because the configuration sync runs later in the process (either installing or updating/syncing) so hook_install() and hook_updates() are the wrong place. Worth mentioning that devs can "abuse" hook_install() and run CRUD operations on installing a module because through the normal module install the hook is fired after the config/install config is added - while during a sync it is the other way around.
Using and abusing the wrong hooks is wrong and dangerous, but this is not mentioned anywhere in the current documentation.
I've updated the IS adding a task for updating some - if not all - of these documentation. Mainly hook_install(), hook_update() and https://www.drupal.org/docs/8/creating-custom-modules/include-default-co... page.
A simple "Use hook_post_config_import_NAME to run CRUD operations against your module default configuration" should be enough.
I'm happy for this task to return to be a different issue if you think it's too out-of-topic.
Comment #4
jibranComment #5
gambry@jibran doesn't that change the scope of the issue? I thought the hook was meant to run after config imports, i.e
drush cim, installing a module with default config, configuration sync from th UI, etc. ?Comment #6
bircherAttached a first patch.
I chose to call the hook
hook_post_config_import_NAMEbecause even though it is part of the update system and works the same way it is used after each config import.The reason for this is that we want to establish best practices for deployments and the issue that prevents config imports before update hooks are run is blocked on the usability that currently developers "enjoy" by using update hooks to update content after configuration changes.
Currently to achieve this one has to import configuration in the update hook itself. (akin to revering features in update hooks in D7...)
Comment #7
fgmActually, doing it in the update hook is just the simplest (but more fragile) way. What I've done in a recent project is add a deferred update process in update hooks, which builds a log of tasks to perform. The specific deployment script for this site then runs the tasks in this log after the updb and entup steps, once everything is done, ensuring a complete database and config schema update. We mostly use it to run migrations and update translations.
Of course, this is site-specific, but it could be extended for more general support. It also has the advantage of not adding just one more specific hook like this one, but providing a more general final step for updates.
Comment #8
bircheryes of course it is possible to do all sorts of things in update hooks.
Until we moved to post_config_import hooks we used post_update hooks and added a config condition and threw an exception, so that you can run update hooks, then import the configuration and then re-run the failed update hooks that expect the configuration to be the new one.
The point is that it is not just about updates but about the whole deployment. Where you run update hooks but also config import, and yes also maybe migrations depending on the site.
Adding another hook is just one solution since #2762235: Ensure that ConfigImport is taking place without outstanding updates is essentially blocked for DX reasons. I would also prefer a shiny and testable deployment API that can handle code changes and config changes and fixes content in all cases, but I would ague that since we have update hooks we might as well have update hooks after config imports and my patch in #6 does that by re-using the post_update hook system code.
I don't know what the long term plan is for dealing with updates and deployments, I can live with hooks in their special files in the mean time.
But by all means, please share more elegant solutions!
Comment #9
fgmJust an idea that crossed my mind reading your explanations: could we not just use many more kernel events and dispatch them more liberally when it comes to updates/imports instead of relying on strictly defined hooks like this ? that way, without having to define a lot of specific hooks, various scenarios would be available.
Of course, the matter of supporting a sandbox/batch mechanism in these might be an issue.
Comment #10
bircher@fgm that would not be a bad idea per-se I would say. However, the nature of update hooks as running once and executing code one time is kind of the goal. An alternative would be to introduce a concept of "deployments", that would be a set of configuration to deploy and a set of update hooks and a set of other instructions that should happen before and after the import of the configuration. But that is very different from workflow to workflow and i guess happens in most cases with git tags anyway. Since the update system already has the concepts of running code once for a certain "update" I think it makes sense to borrow that code and those concepts that developers are already familiar with.
Attached is a patch fixing a
Division by zero ConfigImporter.php:670error that resulted from an obvious oversight.Comment #11
gambryI think we need a definitive answer to @fgm question. I thought the - long time - plan was to move from hooks to events anyway, so we need to make sure the introduction of a new hook is strictly required.
Yeah, I agree. But I think it's much simpler to document "Use
$dispatcher->addListener(ConfigEvents::IMPORT, 'mymodule_post_import');in your hook_install()/hook_update_N() to make use of your config" for instance, instead of having a new hook in a new file-name-convention.And it's for us 0 time implementation too. (Unless we want to add things like the batches process definition capability to event subscribers)
A part from being something developers are used with, what are the other benefits of hook_post_config_import_NAME() compared with adding a listener, either from mymodule.services.yml or
$dispatcher->addListener(ConfigEvents::IMPORT, 'mymodule_post_import');in your install/update hooks()?Don't get me wrong, I'm in favour of hook_post_config_import_NAME() but I want to make sure we have considered and excluded all the other options.
Comment #12
andypostYou can't use event dispatcher in update hooks, because container incomplete at this stage & you need to wait all update hooks passes before core will run in predictable way.
Adding hook does not require a state saved - pure runtime, so I see no ability to use events while we have no "installler kernel"
Comment #13
bircherYes one can make a custom module and add a
ConfigEvents::IMPORTand inject state to it. Then you load a value - say'myproject_deployment_version'- and have a big and/or evolving if/else statement where you put the code you would like to execute for a certain deployment and then set the state value to indicate that the code has run.Since you never call update.php from the web and use drush for importing the configuration you don't need batching as you can just make the cli never time out, so that problem is solved.
But of course you can also just add a custom drush command that runs the code you want to run as part of your deployment and call it after the config import.
There are certainly lots of ways one can execute code in a programmatic way to set values of newly added fields etc.
But all of the ways require some creativity as there is no guidelines or documentation or best practices for it and this issue exists for the sole purpose of
as required by catch.
Remember that this issue is not per-se about "updates" but rather about "deployments" which is not really a core concept at the moment. The goal is to make sure the workflows execute the different steps in a safe order. And at the moment many developers import the configuration before running the update hooks so that they can use update hooks for convenience. There was even an issue for drush to split the running of update_N hooks and post_update hooks so that one can import the configuration in-between for convenience.
I am also happy to not add the hook to core and instead make the update hook system extensible, then I will make the github repo into a proper module, add tests and then we can unblock the core bug and say "use the contrib module if you want convenience or use an event in your custom code."
Comment #15
duaelfr@bircher You are my savior! I just ran in the exact problem you mentioned in the IS: having to populate a freshly created field.
The patch works like a charm.
Would you please update the remaining tasks so I know how I can help? :)
Comment #16
mikran commentedcode looks good but documentation is outdated,
hook_post_update_NAME documentation was wrong, see #2931047: hook_post_update_NAME documentation is misleading
that same wrong documentation is copy pasted to this patch so the copy paste needs to be refreshed here too.
Comment #17
jonathanshawRe # 9 / #11
@fago gave 2 arguments in #2762235: Ensure that ConfigImport is taking place without outstanding updates in favor of why a hook for this use case not relying simply on events:
Comment #18
miiimoooThis is great work @bircher
I like the ease with which you can just add these using the hook.
One problem we found is that the hook seems to get called twice. At least for us in two independent projects.
Comment #19
miiimoooLooks like the duplication is only in what is outputted when running drush config-import. The function is only called once.
Comment #20
miiimoooRe-rolled against 8.6 and added a trivial test to check whether the new hooks are found by the registry.
One thing I realised thanks to writing the test is that given a config_import file with
The functions will be called in alphabetically sorted order: so _a before _b
Comment #21
miiimoooDoes this need any more tests?
Comment #22
jonathanshawNW for #16
Comment #23
mlncn commentedThis addresses #16. It only changes that comment.
(Sorry i have no interdiff game— "The next patch would create the file /tmp/interdiff-1.o7b0ED, which already exists! Assume -R? [n]" and "interdiff: Error applying patch1 to reconstructed file") are breaking my attempts.) Here's the only difference though:
This exciting patch should be ready to go into Drupal core now!
Comment #25
mlncn commentedOK, correct contents of file. Interdiff still same recalcitrant, only change is as per above.
Comment #27
duaelfrThis is a straight reroll of #20 on the latest 8.6.x
Next step is to merge with changes from #23 and #25 with a proper interdiff.
Comment #28
duaelfrHere we go with
hook_post_config_import_NAME()docblock updated!Comment #29
duaelfrI need this one for a project. It's the same as #28's but for 8.5.x.
Comment #30
jonathanshawI think the IS needs updating:
Is it the intention to create a pre import hook here?
Comment #31
duaelfrUpdated IS. You are right, the pre_import hooks are not covered by this issue.
Comment #33
dajjenReroll patch for 8.6.x branch of drupal core
Comment #35
dajjenAhh didn't saw that #28 had a patch working for 8.6.1
Comment #36
Anonymous (not verified) commentedDoes the status of this ticket need updating? I've managed to apply #28 successfully to 8.6.x
Comment #37
prineshazar commented#28 applied cleanly for me too on 8.6x and is part of our distribution. Thank you to all involved.
Comment #38
dajjenComment #39
gemalmThe patch #28 works for 8.6.3
Comment #40
dajjenComment #41
alexpottWhich patch is RTBC? The last patch uploaded to the issue should be the RTBC patch. As far as I can tell that's the patch in #28.
I'm still quite confused about having an event and a registry. The issue summary justifies adding the registry and calling the methods - I'm not sure why the solution requires another event. I think doing both an event and registry complicates what code is supposed to do trigger post import actions as this patch introduces 2 new ways to respond to a config import but it only really wants you to do one - hook_post_config_import_NAME() - but code could listen to the event and do stuff.
I'm also still suspicious that this is the wrong solution. The requirements are always going to be very custom and so I'm not sure why the answer is to add complexity to do address this. For example, taking the rationale in the issue summary - populating a field after adding it. Another way to achieve this would be to script your deployment with something like:
Building an API to do this implies that either core or contrib has a need for this and as far as I can see they don't.
Comment #42
jonathanshawYour solution of a drush script works for custom content in a project (because the project owns the deployment steps and can customise them for its case) but it doesn't work in a contrib module that has to be deployment-agnostic.
Without this proposed hook, is there a way a contrib module can update existing content in a way that depends on new configuration? e.g. if a module wants to rename a piece of configuration it provides which is referenced from an entity reference field.
No idea how much this case matters, just trying to figure out what the use case for this hook must be ...
Comment #43
nicrodgersWe've used the hook provided in this patch for the following (different) use cases:
1. Deploy a new vocabulary (using cim) then post_cim hook to create terms in it. (updb runs before cim, so we couldn't use an update_hook to create them because the vocab wouldn't exist yet).
2. Add a new field to a content type (using cim), then post_cim hook to populate it for existing content based on other field values. (updb runs before cim, so we couldn't use an update_hook to create them because the vocab wouldn't exist yet).
For both of these cases, without the hook in this patch, we didn't see any other way to achieve this in a single automated deployment. In our environment, we don't have the option to run drush scr my_post_import_script.php after a particular deployment (well, not easily anyway).
Comment #44
alexpott@jonathanshaw I think it is very questionable when contrib has content that it thinks it should upgrade. There are many factors that could have affected such content before the upgrade occurs. For example in core where we have the umami demo profile we are explicitly saving we're not providing update paths.
@nicrodgers can you detail the restrictions you are facing? How are you doing your automated deployment?
Comment #45
mpotter commentedChiming in here because I just ran into this exact issue.
1) Added a new field to a vocabulary.
2) Exported config
3) Need to set the value of this field for existing terms, so wrote an Update_N hook for this.
4) Deployed to QA, which runs "updb" and then "config-import"
5) Because updb runs first, the Update_N hook skips the code because the new field does not yet exist
6) Config-import creates the new field
7) Result is that existing terms don't have the correct values for the new field.
Yes, I could (and did) write a drush script to also set these new field values. However, when you are using various hosting providers you don't often have control over the deployment workflow and can't just add any new drush command that you want. Their standard deployment script does "updb" followed by "config-import" followed by a cache-clear.
I could add my own deployment web hook to add this new drush command, and then do a *second* deployment where I removed the hook (cause I'd only want it to run once). But that's super annoying. Need to remember that people don't always have full access or control to their development pipeline.
Thus, we very definitely NEED a way to perform an action after doing a config-import. I don't care if it's an Event or a Hook (although a hook is easier for devs already used to the hook_UPDATE_N process).
We are also talking about this in the CMI 2.0 discussions as there are even more cases where using the Update_N hook for config changes causes problems. So clearly we need a way to separate config updates from general updates.
Comment #46
nicrodgersOur scenario is exactly the same as what @mpotter describes above.
Comment #47
benoit.condaminet commentedWe need this too. We are maintaining D8 websites and this use case often appears.
For example we need to upgrade existing website and migrate fields from plain text to formated text, so we need to add batch post config import hook to update entities.
It really matter when the website is already online and we have config updates, sometimes content must be updated too after config import.
Comment #48
jonathanshawReuploaded #28, resetting to RTBC as various answers to @alexpott's questions have been given.
Comment #49
jonathanshawComment #50
brayfe commentedApplied the patch in #29 to a production environment running Drupal 8.5.1 and it worked like a charm. Definitely agree developers need a consistent method to run entity updates after importing config changes, now that config management is king.
Comment #52
alexpottComment #53
danny.m commentedRerolling #28
Comment #54
danny.m commentedRerolling #28
Comment #55
danny.m commentedRerolling #28
Comment #56
danny.m commentedRerolling #28
Comment #58
larowlanThis will delete the fact that we've previously run hooks in an earlier import - is that the intention - should these hooks re-run on every new config import or on just the first one. I suspect its the later, in which case I think there is a bug here and that also indicates a lack of test coverage. So we likely need some actual test modules implementing this and integration tests.
The logic will go like so
- sandbox is empty
- set finished hooks to []
- fire the event with empty finished
- PostConfigImportUpdateSubscriber::onPostConfigImport event listener is fired
-
$this->updateRegistry->registerInvokedUpdates($event->getFinishedUpdateFunctions());is called- any previous update hooks from an earlier run are replaced with []
- UpdateRegistry::getPendingFunctions will find stuff that had fired in the last import
I think a comment here that indicates we fire this every time intentionally so that we can pass along the list of completed hooks is useful.
should we add a BC layer here to trigger_error if $update_type is NULL (indicating the old signature) and default it to 'post_update'?
Comment #59
mile23I'm coming at this issue because I can't find documentation of what
ConfigEvents::IMPORTactually means.It says:
it doesn't say 'This event is fired after configuration has been successfully imported.'
Therefore, when I see:
...the existence of
POST_CONFIG_IMPORTimplies that my assumptions aboutIMPORTare incorrect, and maybe it fires before the import occurs.Because I literally don't know, I can't tell you to make
IMPORTsay 'happens after the import but beforePOST_CONFIG_IMPORT'. But I would if I knew it was correct. :-)So if
POST_CONFIG_IMPORTis there only to support running hooks after event subscribers have finished, then I'd suggest that a) it not be a separate named event at all, or b) be thoroughly documented as a 'private' event used by core.Comment #60
quex commentedAfter applying patch from #56 the /admin/reports/status crashes with error:
Comment #61
quex commentedSmall bugfix for #60
Comment #62
m4oliveiOne other workaround to add to those already suggested, use a queue. I've run up against the same use case, and I've found that creating a new QueueWorker plugin works well. Define an update hook, query for the records you want to manipulate, queue their entity_id's in your custom queue worker. Define the queue as a cron queue, and have it do whatever you need to do (for instance copy old field values to a new field). It's guaranteed to run after deployment, after updb and cim have finished. It has the added benefit of distributing the performance impact and running in the background. You can also force it to run as part of your deployment script if you need it right away and are uncomfortable with leaving it to happen on cron (eg.
drush queue:run my_queue_name).Comment #63
rp7 commentedSame use-case as #45. This hook would be very welcome.
Comment #64
plopescOur scenario was quite similar to #45 and patch in #61 saved our day.
Would be great to have something like this in core.
Comment #66
claudiu.cristeaI'm quoting myself from a comment I made on #2762235: Ensure that ConfigImport is taking place without outstanding updates:
As an alternative to #2901418: Add hook_post_config_import_NAME after config import, we're using this sequence, in order to run content manipulations with the new installed modules and updated configs:
In this way we are able to run content manipulations, in
hook_post_update_NAME(), that are relying on the updated configs and new modules installed byconfig:import. And this was supposed to be the initial scope ofhook_post_update_NAME(), to run updates on top of the healed API. With config import, we're installing new modules & updating config, and that is part of “fixing the API”, in the same way ashook_update_N()is.Adding a new type of update would only confuse more de developers. My proposal is to:
update.phpto include config import before post updates.Comment #67
daniel.pernold commentedAdd patch from quex for Drupal 8.8.0-alpha1.
Comment #68
norman.lolCan this hook be triggered in a module that's only activated during the same configuration import?
Let's say I'd like to create demo or default content from a module upon its initial installation that happens via configuration import.
Comment #69
bircherAttached is a patch addressing the feedback about why creating a new event, so instead of dispatching an event we just use the service directly. It still needs tests.
#66 is also not the right approach because it requires separating the update and post_update hooks Drupal core and its UI do not allow you to do that and so it seems to me like the wrong approach. (In fact I would argue it is the same problem for which the issue was created in the first place.) This approach happens to work now, but it is a workaround and not a solution in my opinion.
That said I think we should close this issue as won't fix.
As @alerxpott said in #41 we are supposed to run a extra drush command with things that happen for a deployment after a configuration import. Experience has shown me that this is a much better idea than to have a hook that always fires after a config import. Sometimes one just wants to run things individually.
But we also want the convenience of the update hook! so how can we solve this dilemma? A new update hook that gets invoked by a new drush command.
Comment #70
rp7 commentedWe used the patch in #67 several times now. The only drawback that there is no batch support via Drush yet. Pretty sure we'll be using it in the future as well. We add new fields on a regular basis and some of them need to have a default value, and that default also needs to be applied to existing entities. This to make sure they can be correctly filtered/sorted by through our Drupal-provided API (GraphQL in our case, but could very well be JSON:API).
I'm interested to hear a little bit more on that experience. Can you elaborate on the drawbacks you came across?
But the solution this issue is providing is not stopping you from doing that, right? It's merely providing a solution for people who do want to automate it. Going by the comments, these are not isolated cases.
Thanks for pointing me to the drush command. However, how is this less of a workaround for this particular issue then, for example, splitting up the update/post_update hooks during deployment?
Comment #71
duaelfrIf it can help someone, now we (@Happyculture) have been properly introduced with
hook_post_update_NAME(), we use a deployment script that looks like the following:This has worked for every strange use case encountered for the last 2 years.
As we know it's going to work like this, we can choose to use a
hook_update_N()and/or ahook_post_update_NAME()according to our needs.Comment #72
amaisano commented#70:
Isn't using the
&$sandboxfeature akin to batch processing? All of my post_update hooks (and some of my install/update hooks) use this feature to chunk operations and avoid timeouts for large data sets (1000s of nodes).#71:
I believe drush'ing db updates automatically sets and then unsets the site maintenance mode for you - it doesn't need to be done again manually (might speed things up for you).
Comment #74
dropa commented#67 no more applying with 8.9.0
Comment #75
mrinalini9 commentedComment #76
mrinalini9 commentedRerolled patch #67 for 8.9.x, please review.
Comment #77
mrinalini9 commentedComment #78
mrinalini9 commentedPlease ignore patch #76, here is the rerolled patch for 8.9.x, please review.
Comment #79
mrinalini9 commentedComment #80
nicrodgersSetting back to needs work due to the test fail in #78
Comment #81
andypostIn related the same registry gonna be introduced for
hook_update_N()Comment #82
catchFixing the test fail in #78.
Comment #83
moshe weitzman commentedInspired by #69, Drush has implemented a new hook and a command that runs it. Also there is a new 'deploy' command that runs much of the deploy sequence. See https://github.com/drush-ops/drush/pull/4359.
As mentioned in #69, IMO this issue should be closed.
Comment #85
andypostI really like to make factory reusable, it helps to figure where old update_N hooks should move in semver era
Sounds like "Numbering" of updates no longer useful and could be build upon this kind of registry factory
needs separate issue to fix, scope creep
there's 2 kinds of update hooks but both is not ones talked here.
As this event is specific to config import... the post config import updates, I guess
No reason to pass new "update type" because collections expose it via
\Drupal\Core\KeyValueStore\KeyValueStoreInterface::getCollectionName()So less API changes
Comment #86
andypostFiled #3156123: Fix MissingContentEvent see reference for #85.1
And patch address the rest + another follow-up for event base class #3156126: Make MissingContentEvent extend non-deprecated event class
Comment #88
larowlanI think we need to get explicit buy-in from a Framework Manager here, before more work is done.
From #41 @alexpott said
To save more effort, lets pause and get buy that buy in.
Comment #89
catchfwiw I did the re-roll in #82 because I needed the overall feature for a project, but I think the drush deploy support is a better option here, and we should probably mark this duplicate.
Comment #90
artusamakJust a reroll of #78 for 8.9.x.
Comment #91
artusamakWrong patch file for 8.9.3. Sorry, fixed now.
Comment #92
norman.lolNo one has answered to #2901418-83: Add hook_post_config_import_NAME after config import yet.
Indeed
drush deploy:hookordrush deploypicking upHOOK_deploy_NAME()after configuration import seems to solve the request absolutely fine for everyone using Drush. The fact that the development onhook_post_config_import_NAMEcontinues can only be explained by the need to still have a hook to be picked up when people trigger the configuration import from the UI, I guess?!Comment #93
prudloff commentedNote that Drush 10 calls the UpdateRegistry constructor directly, so we had to patch it like this to avoid a crash.
Comment #95
norman.loldrush deployadded in Drush 10.3.0 really is a bliss. I had some new fields added via config that then needed to be populated programmatically after config import.1. Create a
MYMODULE.deploy.phpfile.2. In there implement
MYMODULE_deploy_NAME(&$sandbox), where NAME can be 8001 for example.3. On prod run
drush deploywhich first performs updb, then config import and after that picks up the deploy hook.I think this issue is already resolved. Only documentation updates are missing.
Comment #96
bircherOk lets mark this issue as closed.
I created it, I wrote the first patch and I contributed to the drush command. I think I am qualified to close this.
Then based on recent comments #41, #69, #83, #89, #95 I think it is best to close this issue. Otherwise we risk of wasting more effort implementing a feature that is already solved in a better way.
We should of course update the documentation but that doesn't need this issue. The drush command could of course also be improved (for example by adding batching which this approach here could never do)
Comment #97
norman.lolhook_deploy_NAME(&$sandbox)already contains batching capabilities same ashook_update_N(&$sandbox).Comment #98
jwilson3Question: does the 8001 in the suggestion above imply that Drush handles not running these commands multiple times after every deploy, similar to how Drupal core handles not running hook_update_N more than once by tracking the schema version in the database? I would assume this is not the case, and then this solution doesn't really solve the one-off case needed where you want to run a single task once *after* having run drush cim.
Our specific use case:
In a single deployment, enable a module and import field definitions for a new content type from config/sync folder (done during the drush cim step) then execute hook_update_N to create some content. We've placed a reference to the hook_update_N inside the hook_install() function but we're seeing that modules enabled with drush cim do not consistently execute to programmatically create the default content. It could also be that the hook_update_N, being called by hook_install is trying to run *before* the config and fields have been created, and therefore fails to create the content.
Comment #99
moshe weitzman commentedThe same Drupal registry that prevents rerunning post_update functions also prevents rerunning MY_MODULE_deploy_NAME functions so your scenario of one off content important is a great use case for MY_MODULE_deploy_NAME.
Comment #100
norman.lolYour assumption is wrong.
hook_deploy_NAME(&$sandbox)behaves the same ashook_update_N(&$sandbox). Every implementation only runs once. And it only automatically runs after configuration import when callingdrush deploybecause there the order of sub-commands is set (updb, cim, hook:deploy).What you describe is another problem I think. It only happens when installing a module from configuration import. But doesn't happen when you manually enable the module, right? I experienced the same and then always solved creating dummy content by providing a custom admin form or another custom Drush command for it to be manually triggered later. It seems as if sometimes when you try to provide dummy or default content from
hook_installdoesn't happen during config import because other dependencies are not met yet. Maybe module config not being picked up or registered yet.It would be good to have that as another issue. Maybe with a step-by-step on a Vanilla Drupal. Like when you create taxonomy terms inside
hook_installthey are created during manual module activation but not if the module gets activated during configuration import. If that's the case.Comment #101
jwilson3Correct, this is indeed the case we're seeing. We haven't figured out exactly what the issue is, but problem happens for both nodes and taxonomy. Running drush cim twice seems to fix the issue.
the update_N even goes so far as to *create the taxonomy/node type, before creating the dummy content, but it doesnt work correctly. Perhaps, yes, this is a separate issue, but in theory, couldn't it be solved then by moving to hook_deploy_NAME()?
Out of curiosity, where does drush track this?
Comment #102
norman.lolI'd assume that any implementation of
hook_deploy_NAME(&$sandbox)same ashook_update_N(&$sandbox)never runs during installation of a module. It just gets registered. And then when during an update of an already installed module a new implementation gets added only these are run. But that's an assumption. Maybe Moshe can clarify.Comment #103
moshe weitzman commentedhook_deploy_NAME is most analogous to hook_post_update_NAME, and not hook_update_N. hook_update_N has a different tracking system because its names are sequential. post_update and deploy are non-sequential names.
None of these functions run during module installation. They are run by updatedb (UI or Drush) and deploy (Drush), and nowhere else.
I'm not too sure whats causing that, but it sounds like a Drupal core issue, thats separate from this one. It couold be Drush at fault, but I wouldn't bet on it.
Comment #104
frobIs Drush supposed to be a dependency of running Drupal now? While it is great that Drush was able to add this functionality so quickly, it seems to me that this is something that would be better off in core.
Comment #105
norman.lolPlease support #3159647: Add drush/drush to Drupal Composer project templates and keep things DRY. Thank you
Comment #106
norman.lolBut yes, maybe a good reminder to open a new issue to implement the UI to run deploy hook implementations same as /update.php from the browser.
Comment #107
norman.lolVoilà!
#3206497: Define new hook_deploy_NAME hook and add new route to run their implementations from the UI
Comment #108
matt_paz commentedNot sure it makes sense to close this as a duplicate b/c it could be desirable to have core support this, but
drush deployseems to work great for me nonetheless.Comment #109
awm commentedI agree with @matt_paz.
I'd love to have this as well in core. It would give us more flexibility . BLT for example does not incorporate deploy and they decided against adding to the blt piplines: https://github.com/acquia/blt/issues/4252.
Comment #110
bircherRE #108 and #109: Yes it would be lovely in core, but not as a post config import hook. (That turned out to be a bad idea, I know, I came up with it and I used it in production). The much better idea is the deploy hook which we would like to add support for in drupal core in #3206497: Define new hook_deploy_NAME hook and add new route to run their implementations from the UI. So go and support that issue with a patch or by talking to your friends about it.
Comment #111
marcoscanoAlso worth noting that
drush updatedbhas a--no-post-updatesoption, so you could set up your build processes to runupdbfirst for the numbered updates only, then import config, and then runupdbagain, which would then run post-update hooks _after_ the config is imported. This avoids the need to write deploy hooks in a separate file/hook type.This is what https://github.com/Lullabot/drainpipe/blob/main/tasks/drupal.yml#L39 uses, if it serves as a reference.
Comment #112
apotek commentedSo, in conclusion.
1. The hook that runs database updates is called `hook_update_N()` and lives in the .install(!) file.
2. The hook that runs updates right after the updates and before anything else is done is called `hook_post_deploy_NAME()` instead of (the more logical) `hook_post_update_NAME()`.
(No, developers, `hook_post_deploy_NAME()` does _not_ run after the deployment, even though it is named as though it would and even though it is located in a file called MODULE.post_deploy.php, and not in the .install file where its sibling `hook_update_N()` is.)
3. Instead of simply providing a way to run steps truly after a deployment has run as requested, the solution is.... a new requirement! You must install drush, and be able to use drush in your environment. Or, you have to do a separate step in the UI.
4. The name of the hook that the Drush project decided to use to run events after a deployment is called :drumroll: .... `hook_deploy_NAME()` and lives in a MODULE.deploy.php file! I kid you not.
After 111 comments and many rejected patches, this is where we are.
Comment #113
duaelfr@apotek Hi! I think there is a small misunderstanding.
Drupal Core provides two different hooks to manage updates:
-
hook_update_Nwhose implementations have to be located in .install files and are ran sequentially from the lowest to the highest N value for a given module (hook_update_dependenciescan declare dependencies between hook updates from different modules)-
hook_post_update_NAMEwhose implementations can be located in a .post_update_.php file and are ran sequentially in alphabetical order (these cannot declare dependencies)Both these hooks are executed when running
drush updbor using theupdate.phproute.It was once possible to separate them with the
--no-post-updatesoption in drush but it is not available anymore.The need described in this issue was to be able to run code once (like those hooks), after the configuration has been imported because update hooks are meant to be ran before config import. The proposal was to introduce a new
hook_post_config_import_NAMEhook but it turned out to be a bad idea because we were trying to solve an issue related to the deployment process and not the update process.This is when drush released their
drush deploycommand which was running updates, then config import, then a brand new hook they created:hook_deploy_NAME. This solved all issues mentioned above so the development of this post import hook was abandoned.But, as some people pointed out already, drush is not part of the Core so it would be better to have this in Core than only rely on an external dependency. That's why this issue has been opened (even if its current title can be misleading) .
I hope this helps you understand the current status of this and consider pushing this topic forward in the related issue.