EventManager/Eventlisterners unterscheiden sich bei Cron Ausführung CLI vs Browser

Guten Tag liebste Gemeinde,

tldr;

Warum unterscheiden sich die registrierten cron Eventlistener auf CLI und im Browser?

ich habe folgendes Problem. Ich habe diverse SW5.1 und älter Plugins geschrieben welche Cronjobs beinhalten. Registriert wurden sie alle gleich und wie folgt (Bootstrap::install()):

$this->subscribeEvent(
    'Shopware_CronJob_MeinCronJob',
    'onRunMeinCronJob'
);

Funktioniert beim Großteil der Plugins einwandfrei, und die Cronjobs lassen sich sowohl über den BackendController " https://domain.de/backend/cron" als auch über die CLI ausführen " sw:cron:run -f MeineCronAction". Aber seit kurzem habe ich vermehrt das Problem das einige dieser Cronjobs sich lediglich über den BackendController ausführen lassen. Bei Ausführung über die CLI steht zwar da " Processing MeinCron…", aber er läuft nicht mal in die zugehörige onRun Funktion hinein.

Nach einigem Debuggen habe ich nun festgestellt, dass auf der CLI die benötigten EventListener nicht zur Verfügung stehen und er daher in der EventManager::notifyUntil Funktion direkt am Anfang beim ersten IF statement aussteigt.

public function notifyUntil($event, $eventArgs = null)
{
    if (!$this->hasListeners($event)) {
        return null;
    }
...

 

Wie gesagt, bei Aufruf über den Cron-BackendController stehen diese aber zur Verfügung und der Cron wird ohne weiteres ausgeführt. Wenn man sich die beiden Cron Anlaufpunkte genauer anschaut, sehen die soweit eigentlich gleich aus.

class Shopware_Controllers_Backend_Cron extends Enlight_Controller_Action implements CSRFWhitelistAware
{
    public function init()
    {
        Shopware()->Plugins()->Backend()->Auth()->setNoAuth();
        Shopware()->Plugins()->Controller()->ViewRenderer()->setNoRender();
    }

    public function indexAction()
    {
        if (!Shopware()->Plugins()->Core()->Cron()->authorizeCronAction($this->Request())) {
            $this->Response()
                ->clearHeaders()
                ->setHttpResponseCode(403)
                ->appendBody('Forbidden');

            return;
        }

        /** @var $cronManager Enlight_Components_Cron_Manager */
        $cronManager = Shopware()->Cron();

        set_time_limit(0);
        while (($job = $cronManager->getNextJob()) !== null) {
            echo 'Processing ' . $job->getName() . "\n";
            $cronManager->runJob($job);
        }
    }

...

class CronRunCommand extends ShopwareCommand
{
    ...

    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->registerErrorHandler($output);
        $this->container->load('plugins');

        /** @var Enlight_Components_Cron_Manager $manager */
        $manager = $this->container->get('cron');

        $cronjob = $input->getArgument('cronjob');
        $force = $input->getOption('force');

        if (!empty($cronjob)) {
            try {
                $this->runSingleCronjob($output, $manager, $cronjob, $force);
            } catch (\Exception $e) {
                $output->writeln('' . $e->getMessage() . '');
                $output->writeln('Please use the action name of a cronjob. You can see existing cronjobs in shopware backend or via sw:cron:list command.');

                return 1;
            }

            return 0;
        }

    ...
    }

    /**
     * @param OutputInterface $output
     * @param Enlight_Components_Cron_Manager $manager
     * @param string $cronjob
     * @param bool $force
     */
    private function runSingleCronjob(OutputInterface $output, Enlight_Components_Cron_Manager $manager, $cronjob, $force)
    {
        $job = $this->getJobByActionName($manager, $cronjob);

        if (!$this->allowRun($force, $job)) {
            return;
        }

        $output->writeln('Processing ' . $job->getName());
        $manager->runJob($job);
    }

...

Systeminfo :

Shopware 5.2.26

PHP: 5.6.30

OS: Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-66-generic x86_64) (Shopware vagrant VM) (tritt aber auch beim Kunden auf)

Webserver: Apache

Die initialisierten Job Objekte sehen identisch aus, und auch wenn ich im CronCommand „$manager = $this->container->get(‚cron‘);“ wie im BackendController über „Shopware()->Cron()“ lade bleibt das Ergebnis das gleiche. Ich habe auch bereits testweise im CronCommand den ShopContext registriert, aber auch das brachte keinen Erfolg.

Bei 5.2 Plugins trat dieses Problem bisher noch nicht auf.

Jemand eine Idee woran das liegen könnte, dass sich die registrierten EventListener zwischen CLI und BackendControllern unterscheiden? Und wie ich bewirke, dass dem nicht so ist?

Beste Grüße

Daniel

Hallo Daniel,
ich hatte ähnliche Probleme. Nachdem ich den Cronjob, welcher ausgelagert war wieder in der Bootstrap.php gepackt habe, läuft es wieder korrekt in der CLI.
Der Zusammenhang ist mir aber schleierhaft.

Evtl. hat jemand anders ebenfalls diese Erfahrungen gemacht?

MFG ottscho

1 „Gefällt mir“
  1. Habt ihr die Event-Listener-Funktion (subscribeEvent(…)) wirklich in der install-Methode aufgerufen? Steht dieser dann in der s_core_subscribes-Tabelle?
  2. Falls nein: Habt ihr eine Event-Subscriber-Klasse verwendet?  Wenn ja: Wann fügt ihr diese in das Shopware Event System hinzu?
    1. Im …_Front_StartDispatch bzw. Route-Startup Event? => Das wird nur bei Frontend-Requests getriggert. Ihr müsst euren Event-Subscriber daher früher hinzufügen/anmelden. Für CLI am besten zusätzlich beim Shopware_Console_Add_Command. Siehe auch hier. Lange Zeit war dies nicht ausführlich dokumentiert. Ich denke hier liegt der Fehler
  3. Falls ja: Zeig mal deine Bootstrap. Das sollte eigentlich funktionieren.  Frown

Dies gilt nur für das alte Plugin System. Im neuen System werden die Subscriber-Klassen früh genug geladen.

 

tldr;

tldr;

Warum unterscheiden sich die registrierten cron Eventlistener auf CLI und im Browser?

Die _Front_StartDispatch und Route-Startup Events werden nur bei HTTP-Requests ausgeführt. Im CLI gibt es ja gar keinen richtigen „Request“. => Eure Event-Listener Klassen werden mit hoher Wahrscheinlichkeit gar nicht hinzugefügt. Nutzt zusätzlich das Shopware_Console_Add_Command-Event um eure Event-Listener Klasse „anzumelden“.

Viele Grüße 

1 „Gefällt mir“