Why does the sw:cron:run CLI command not trigger my subscriber?

Hi everyone,

since I’ve been sitting over this issue for at least 2 days while digging into the Shopware Core I now decided to try my luck here.

First off you should know that I still use the legacy plugin system since I need to support older Shopware versions.

The following two file plugin should give you an idea, what I do in a bigger scale:

Bootstrap.php:

get('Loader')->registerNamespace('Shopware\\Plugins\\DemoPlugin', $this->Path());
    }

    protected function registerEvents()
    {
        $this->subscribeEvent('Enlight_Controller_Front_DispatchLoopStartup', 'onDispatchLoopStartup');
    }

    public function onDispatchLoopStartup(Enlight_Event_EventArgs $args)
    {
        // Add new Subscriber
        $this->Application()->Events()->addSubscriber(
            new \Shopware\Plugins\DemoPlugin\Subscribers\CronJobs($this, Shopware()->Container())
        );
    }

    /**
     * Custom cron job register logic, since Shopware just adds cronjobs without a check if they exist already.
     * Until they fail to execute later...
     */
    public function registerCronJobs()
    {
        // Define cronjobs here with the action as the key
        $cronJobs = [
            'DemoPluginCron' => [
                'name' => 'DemoPlugin Cron',
                'interval' => 600,
                'active' => 1,
                'disableOnError' => false,
            ],
        ];
        // Get already created cronjobs
        $sql = "SELECT `action` FROM `s_crontab` WHERE `pluginID` = ?";
        $dbJobs = Shopware()->Db()->fetchCol($sql, array($this->getId()));
        if($dbJobs == null) {
            $dbJobs = array();
        } else {
            // Remove prefix "Shopware_CronJob_" from the actions of the jobs in the DB
            array_walk($dbJobs, function(&$element, $key, $prefix) {
                $element = str_replace($prefix, '', $element);
            }, 'Shopware_CronJob_');
        }
        // Difference between our cronjobs and the jobs in the DB
        $jobsToCreate = array_diff(array_keys($cronJobs), $dbJobs);
        // Now create all jobs that were not in the DB
        foreach ($jobsToCreate as $jobAction) {
            $job = $cronJobs[$jobAction];
            $this->createCronJob(
                $job['name'],
                $jobAction,
                $job['interval'],
                $job['active'],
                $job['disableOnError']
            );
        }
    }

    public function unRegisterCronJobs()
    {
        $sql = "DELETE FROM s_crontab WHERE pluginID = ?";
        Shopware()->Db()->query($sql, array($this->getId()));
    }

    /* Irrelevant functions */

    /**
     * Perform all necessary install tasks
     *
     * @param $update bool
     *
     * @return array
     */
    public function install($update = false)
    {
        $this->registerEvents();
        try {
            $this->registerCronJobs();
        } catch (Exception $e) {
            // check if already exists
        }
        return array('success' => true, 'invalidateCache' => array('proxy'));
    }

    /**
     * Uninstall method
     *
     * @param $removeAttributes bool
     *
     * @return boolean
     */
    public function uninstall($removeAttributes = false)
    {
        $this->unRegisterCronJobs();
        return true;
    }

    /**
     * Update plugin, check previous versions
     *
     * @param $oldVersion string
     *
     * @return array
     */
    public function update($oldVersion)
    {
        return $this->install(true);
    }

    /**
     * Activation method
     *
     * @return array
     */
    public function enable()
    {
        return array(
            'success' => true,
            'invalidateCache' => array('proxy'),
        );
    }

    /**
     * Disabling method
     *
     * @return array
     */
    public function disable()
    {
        return array(
            'success' => true,
            'invalidateCache' => array('proxy'),
        );
    }

    /**
     * Deactivation method
     *
     * @return array
     */
    public function deactivate(DeactivateContext $deactivateContext)
    {
        $deactivateContext->scheduleClearCache(DeactivateContext::CACHE_LIST_ALL);
    }

    /**
     * Returns list of actions this plugin is capable of
     *
     * @return array
     */
    public function getCapabilities()
    {
        return array(
            'install' => true,
            'update' => true,
            'enable' => true
        );
    }

    /**
     * Returns the information about this plugin as array.
     *
     * @return array
     * @throws Exception
     */
    public function getInfo()
    {
        return array(
            'label' => "Demo Plugin",
            'author' => "Vincent Mrose",
            'version' => $this->getVersion(),
            'description' => "Demo Plugin",
            'solution_name' => "demoplugin"
        );
    }

    /**
     * Returns the version of this plugin
     *
     * @return string
     * @throws Exception
     */
    public function getVersion()
    {
        return "1.0.0";
    }

    /**
     * Returns plugin label
     *
     * @throws Exception
     * @return string
     */
    public function getLabel()
    {
        return "Demo Plugin";
    }
}

Note the event “Enlight_Controller_Front_DispatchLoopStartup” I subscribe to, to add my Subscriber.

CronJob Subscriber:

bootstrap = $bootstrap;
        $this->container = $container;
    }

    /**
     * returns array with subscribed events
     *
     * @return array
     */
    public static function getSubscribedEvents()
    {
        return array(
            'Shopware_CronJob_DemoPluginCron' => 'onCronRun',
        );
    }

    /**
     * Cron Run function
     *
     * @param \Enlight_Event_EventArgs $args
     *
     * @return mixed
     */
    public function onCronRun(\Enlight_Event_EventArgs $args)
    {
        $logger = $this->container->get('pluginlogger');
        $logger->info('DemoPlugin Cron was executed');
    }
}

Now when you install and activate this plugin and execute the console command
./bin/console sw:cron:run -f “Shopware_CronJob_DemoPluginCron”
to run the cron it should  cause the plugins constructor to write “Demo Plugin got loaded, yay” to the php error log and to write a plugin log entry “DemoPlugin Cron was executed”.

However it does not do any of that in my installation of Shopware 5.6.2.

Only when I execute it via the /backend/cron endpoint it triggers those logging statements.

So my questions are:
Why is the cron subscriber not triggered when the cron:run command is run and only when I do it via /backend/cron?
Does this have to do with the event I use to add my Subscriber (“Enlight_Controller_Front_DispatchLoopStartup”)?
If so, which event should I subscribe to, to get my cronjob executed correctly?
Or am I not able to use separate files for Subscribers in conjunction with the command?

When your in production mode, your Logger will only listen to ERROR and above ( CRITICAL and so on). You should simply add an return „hello“; to see if cron has output. You can see it in the statuswindow of the specific cron. (There where you can arange the time… above).
You could add a die(‚to be sure‘); he goes in there. Just to find your actual  problem location.

When you execute your cron by console like you described and you working on a regualre system, than you might work in production mode. At least on command line.
You can change environment by adding a line like SetEnv SHOPWARE_ENV dev. There are some more other ways… also conditional one.

As long as you dont add the env to your apache configs, your console command will run in production mode anyway.

See: Configuring Multiple Shopware Environments
If you call your console command to execure your cron and you want to run dev mode without adding it to apache, add - -env=dev to your command.

 ./bin/console sw:cron:run -f DemoPluginCron --env=dev

This will execute it in dev mode where you got the loglevel at DEBUG and this will write to the plugin-file inside var/log/

FYI: You dont have to take the whole name to call your cron fom console… DemoPluginCron should be enough :slight_smile: