Como definir o cronograma dinâmico do cronjob do banco de dados no Magento 2

7

Estou trabalhando em um módulo personalizado para Magento 2. Fiz a instalação do crontab lá e está funcionando bem com programação estática.

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../app/code/Magento/Cron/etc/crontab.xsd">
    <group id="default">
        <job name="tm-feed-job" instance="TM\Feed\Model\Cron" method="export">
            <schedule>* * * * * *</schedule>
        </job>
    </group>
</config>

Mas preciso da <schedule>* * * * * *</schedule>dinâmica do valor salvo do meu banco de dados. Aqui eu preciso usar 3 horáriosDaily Weekly Monthly

Frequência já salva no banco de dados insira a descrição da imagem aqui

Como posso adicionar um agendamento dinâmico lá?

Sohan
fonte

Respostas:

10

Não é tão fácil quanto eu esperava.

Primeiro, você precisa atualizar o seu crontab.xmlpara configurar o caminho da configuração para a sua frequência:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../app/code/Magento/Cron/etc/crontab.xsd">
    <group id="default">
        <job name="tm-feed-job" instance="TM\Feed\Model\Cron" method="export">
            <config_path>crontab/default/jobs/tm_feed_job/schedule/cron_expr</config_path>
        </job>
    </group>
</config>

Agora você precisa adicionar um campo à configuração para poder escolher a frequência para adminhtml/system.xml:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <section id="vendor">
            <group id="module" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="0" showInStore="0">
                <label>Cron Settings</label>
                <field id="frequency" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="0" showInStore="0">
                    <label>Frequency</label>
                    <source_model>Magento\Cron\Model\Config\Source\Frequency</source_model>
                    <backend_model>Vendor\Module\Model\Config\Backend\Frequency</backend_model>
                </field>
                <field id="time" translate="label" type="time" sortOrder="2" showInDefault="1" showInWebsite="0" showInStore="0">
                    <label>Start Time</label>
                </field>
            </group>
        </section>
    </system>
</config>

Agora precisamos criar Vendor\Module\Model\Config\Backend\Frequencypara o modelo de back-end de frequência:

<?php

namespace Vendor\Module\Model\Config\Backend;

class Frequency extends \Magento\Framework\App\Config\Value
{
    /**
     * Cron string path
     */
    const CRON_STRING_PATH = 'crontab/default/jobs/tm_feed_job/schedule/cron_expr';

    /**
     * Cron model path
     */
    const CRON_MODEL_PATH = 'crontab/default/jobs/tm_feed_job/run/model';

    /**
     * @var \Magento\Framework\App\Config\ValueFactory
     */
    protected $_configValueFactory;

    /**
     * @var string
     */
    protected $_runModelPath = '';

    /**
     * @param \Magento\Framework\Model\Context $context
     * @param \Magento\Framework\Registry $registry
     * @param \Magento\Framework\App\Config\ScopeConfigInterface $config
     * @param \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList
     * @param \Magento\Framework\App\Config\ValueFactory $configValueFactory
     * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
     * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
     * @param string $runModelPath
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\Model\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\App\Config\ScopeConfigInterface $config,
        \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList,
        \Magento\Framework\App\Config\ValueFactory $configValueFactory,
        \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
        \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
        $runModelPath = '',
        array $data = []
    ) {
        $this->_runModelPath = $runModelPath;
        $this->_configValueFactory = $configValueFactory;
        parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data);
    }

    /**
     * {@inheritdoc}
     *
     * @return $this
     * @throws \Exception
     */
    public function afterSave()
    {
        $time = $this->getData('groups/module/fields/time/value');
        $frequency = $this->getData('groups/module/fields/frequency/value');

        $cronExprArray = [
            intval($time[1]), //Minute
            intval($time[0]), //Hour
            $frequency == \Magento\Cron\Model\Config\Source\Frequency::CRON_MONTHLY ? '1' : '*', //Day of the Month
            '*', //Month of the Year
            $frequency == \Magento\Cron\Model\Config\Source\Frequency::CRON_WEEKLY ? '1' : '*', //Day of the Week
        ];

        $cronExprString = join(' ', $cronExprArray);

        try {
            $this->_configValueFactory->create()->load(
                self::CRON_STRING_PATH,
                'path'
            )->setValue(
                $cronExprString
            )->setPath(
                self::CRON_STRING_PATH
            )->save();
            $this->_configValueFactory->create()->load(
                self::CRON_MODEL_PATH,
                'path'
            )->setValue(
                $this->_runModelPath
            )->setPath(
                self::CRON_MODEL_PATH
            )->save();
        } catch (\Exception $e) {
            throw new \Exception(__('We can\'t save the cron expression.'));
        }

        return parent::afterSave();
    }
}

Esse código parece complicado à primeira vista, mas basicamente gera o crontab/default/jobs/tm_feed_job/schedule/cron_exprcaminho de configuração com base no que você escolheu na lista suspensa de frequência.

Descoberta interessante de observação lateral: isso é implementado para alguns módulos no M2 nativamente, que incluem moeda, alertas de produtos, backups, sitemaps. O interessante é onde o modelo de back-end é definido para alguns desses módulos:

  • Alerta do produto: Magento\Cron\Model\Config\Backend\Product\Alert
  • Mapa do site: Magento\Cron\Model\Config\Backend\Sitemap

Então sim, você leu certo. Em vez de estar na pasta do módulo correspondente, esses modelos de back-end estão localizados na Magento\Cronpasta do módulo.

Raphael na Digital Pianism
fonte
obrigado pela observação - mas queria perguntar o que o runModel está fazendo aqui. Pelase explica #
Abid Malik
Você sempre apresenta uma boa solução. +1 :)
Shoaib Munir
Para que serve runModelPath? É necessário adicionar isso?
DJ Dev
não está funcionando no magento 2.3.3. O cron não é executado conforme o tempo definido na configuração. meu cron é executado às 00:01 todos os dias, mas defini o horário 10:30 e a frequência "Daily".
nil108 22/01
0

Ao analisar \Magento\Cron\Observer\ProcessCronQueueObserver::_generateJobs, seria suficiente criar uma entrada varchar na chave de configuração especificada para que seu respectivo <config_path>valor seja lido core_config_data.

sebastianwagner
fonte