Open driskell opened 5 years ago
I can confirm that this issue still exists in Drupal Console version 1.9.7 & Drupal 8.9.11. Like driskell, I'm also running into this problem with custom Drupal Console commands that save nodes don't queue up cache tags in the purge module.
I haven't fully figured out, but I think that the base Symfony Console is dispatching a ConsoleEvents::TERMINATE
event after the command runs, but not a KernelEvents::TERMINATE
event.
See: https://symfony.com/doc/current/components/console/events.html#the-consoleevents-terminate-event
The purge module tags its queue service with needs_destruction
. It looks like Dupal's KernelDestructionSubscriber::onKernelTerminate()
is responsible for handling the needs_destruction
tag and should be triggered by the KernalEvents::TERMINATE
event. Because KernalEvents::TERMINATE
isn't being dispatched, the destructor never gets called.
I'm not sure what the best way to address this is. Maybe the Drupal Console could subscribe to ConsoleEvents::TERMINATE
and dispatch a KernelEvents::TERMINATE
event. Or maybe this is a bug in Symfony's Console.
It looks like the KernalEvents::TERMINATE
event is normally dispatched by HttpKernel::terminate()
. My hunch is that Symfony Console isn't assuming there there is an HttpKernel, and so is using its own event, but the DrupalKernel
is an HttpKernel
and expects there to eventually be a terminate()
call.
I tried to add a work-around with a very simple module that would listen for ConsoleEvents::TERMINATE
event and call DrupalKernel->terminate()
, but the event never gets triggered. Maybe that's due to the Console event being dispatched in a different container than the Drupal site's code and modules.
console_terminator.info.yml
:
name: 'Console Terminator'
type: module
description: 'Terminates the Drupal Kernel when the Drupal Console terminates, fixing a console bug: https://github.com/hechoendrupal/drupal-console/issues/4025'
core_version_requirement: '^8.0.0 || ^9.0.0'
console_terminator.services.yml
:
services:
console_terminator:
class: Drupal\console_terminator\EventSubscriber\ConsoleTerminator
arguments: ['@kernel']
tags:
- { name: event_subscriber }
console_terminator/src/EventSubscriber/ConsoleTerminator.php
:
<?php
namespace Drupal\console_terminator\EventSubscriber;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\TerminableInterface;
/**
* Listen for ConsoleEvents::TERMINATE and dispatch KernelEvents::TERMINATE.
*/
class ConsoleTerminator implements EventSubscriberInterface {
/**
* The Drupal Kernel.
*
* @var \SSymfony\Component\HttpKernel\TerminableInterface
*/
protected $kernel;
/**
* Construct the object.
*
* @param \Symfony\Component\HttpKernel\TerminableInterface $kernel
* The Drupal Kernel.
*/
public function __construct(TerminableInterface $kernel) {
$this->kernel = $kernel;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
return [
ConsoleEvents::TERMINATE => ['terminate'],
];
}
/**
* Terminate the Drupal kernel when the console terminates.
*
* @param \Symfony\Component\Console\Event\ConsoleTerminateEvent $event
* The event to process.
*/
public function terminate(ConsoleTerminateEvent $event) {
if ($event->isPropagationStopped()) {
return;
}
// Terminate the Drupal kernal.
$this->kernel->terminate(new Request, new Response);
}
}
This leads me to think that a solution will require DrupalConsole to call terminate()
on the command's DrupalKernel.
In case it's helpful to anyone, here's what I had to add to my custom command class as a work-around for this bug, injecting the DrupalKernel service and then calling terminate()
on it:
diff --git a/web/modules/custom/middlebury_event_sync/src/Command/EventSyncCommand.php b/web/modules/custom/middlebury_event_sync/src/Command/
index 55384c0..83e0b52 100644
--- a/web/modules/custom/middlebury_event_sync/src/Command/EventSyncCommand.php
+++ b/web/modules/custom/middlebury_event_sync/src/Command/EventSyncCommand.php
@@ -9,6 +9,9 @@
use Drupal\Console\Core\Style\DrupalStyle;
use Drupal\Console\Annotations\DrupalCommand; // @codingStandardsIgnoreLine
use Drupal\middlebury_event_sync\Service\EventSyncer;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\TerminableInterface;
/**
* Command for syncing events.
@@ -28,10 +31,23 @@ class EventSyncCommand extends Command {
protected $eventSyncer;
+ /**
+ * The Drupal Kernel.
+ *
+ * @var \Symfony\Component\HttpKernel\TerminableInterface
+ */
+ protected $kernel;
+
/**
* Constructs a new EventSyncCommand object.
*
* @param \Drupal\middlebury_event_sync\Service\EventSyncer $eventSyncer
* The EventSyncer service.
+ * @param \Symfony\Component\HttpKernel\TerminableInterface $kernel
+ * The Drupal Kernel.
*/
- public function __construct(EventSyncer $eventSyncer) {
+ public function __construct(EventSyncer $eventSyncer, TerminableInterface $kernel) {
$this->eventSyncer = $eventSyncer;
+ $this->kernel = $kernel;
parent::__construct();
}
@@ -78,6 +94,10 @@ protected function execute(InputInterface $input, OutputInterface $output) {
foreach ($messages as $message) {
$io->info($message);
}
+
+ // Work-around for Drupal-console not terminating the Drupal kernel.
+ // https://github.com/hechoendrupal/drupal-console/issues/4025
+ $this->kernel->terminate(new Request(), new Response());
}
Problem/Motivation
Any command that runs that depends on services running their destructors (@needs_destruction) will not work properly with drupal console.
It seems this was originally in the code but somehow lost in some refactors along the way. See: https://github.com/hechoendrupal/drupal-console/pull/598
How to reproduce
I only have an example with purge module
Install purge module and enable the purge processor cron and purge core tags queuer Disable cron in all ways, but then run via cron using drupal cron:execute When saving posts, the queue is added to When cron:execute command is run, the items are invalided, but not removed from the queue, because purge queue service is not destructed
Drupal 8.6.15 Drupal console 1.8.0
Solution
Use KernelHelper to call terminate after commands are finished