• laravel 计划任务的实现原理


    laravel的计划任务确实好用,之前就计划吧这个功能研究下,自己造一个给tp5使用

    但是研究之后发现,容器这个概念吧代码变得比较抽象,代码读起来的难度比较高

    然后研究之后发现除了phpstorm可以追踪大部分代码之外,其他的ide代码追踪功能真的很一般,比如我一般使用NetBeans

    看官网在开发9.0不知道啥时候了,等等吧

    2018年7月30日11:01:42

    补充:laravel主要使用的是容器来实现功能的注册,绑定,使用的 ,但是我逐渐发现laravel的慢的原因估计也是因为这个,虽然容器实现了对象池,但是大多数的调用还是new,理论上都是在对象池只有一个,但是new的东西太多

    使用起来更容易了,但是代码可读性也越差了,很多IDE都没办法追踪源代码了

    现在对于容器的好与坏,确实有待商榷,现在tp也开始学习这套东西,不知是好是坏

    laravel的实现原理就是利用 crontab 每分钟执行一次

    计算任务的所需要执行的时间,加上互斥保证只执行一次,防止其他用户执行, 判断是否已经执行过

    * * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1

    这个就是官方提供的执行计划任务的crontab脚本

    提供部分代码参考

    public function command($command, array $parameters = [])
        {
            if (class_exists($command)) {
                $command = Container::getInstance()->make($command)->getName();
            }
    
            return $this->exec(
                Application::formatCommandString($command), $parameters
            );
        }

    执行普通命令  php artisan xxxTask

    php artisan schedule:run

    class CronExpression
    {
        const MINUTE = 0;
        const HOUR = 1;
        const DAY = 2;
        const MONTH = 3;
        const WEEKDAY = 4;
        const YEAR = 5;
    
        /**
         * @var array CRON expression parts
         */
        private $cronParts;
    
        /**
         * @var FieldFactory CRON field factory
         */
        private $fieldFactory;
    
        /**
         * @var int Max iteration count when searching for next run date
         */
        private $maxIterationCount = 1000;
    
        /**
         * @var array Order in which to test of cron parts
         */
        private static $order = array(self::YEAR, self::MONTH, self::DAY, self::WEEKDAY, self::HOUR, self::MINUTE);
    
        /**
         * Factory method to create a new CronExpression.
         *
         * @param string $expression The CRON expression to create.  There are
         *                           several special predefined values which can be used to substitute the
         *                           CRON expression:
         *
         *      `@yearly`, `@annually` - Run once a year, midnight, Jan. 1 - 0 0 1 1 *
         *      `@monthly` - Run once a month, midnight, first of month - 0 0 1 * *
         *      `@weekly` - Run once a week, midnight on Sun - 0 0 * * 0
         *      `@daily` - Run once a day, midnight - 0 0 * * *
         *      `@hourly` - Run once an hour, first minute - 0 * * * *
         * @param FieldFactory $fieldFactory Field factory to use
         *
         * @return CronExpression
         */
        public static function factory($expression, FieldFactory $fieldFactory = null)
        {
            $mappings = array(
                '@yearly' => '0 0 1 1 *',
                '@annually' => '0 0 1 1 *',
                '@monthly' => '0 0 1 * *',
                '@weekly' => '0 0 * * 0',
                '@daily' => '0 0 * * *',
                '@hourly' => '0 * * * *'
            );
    
            if (isset($mappings[$expression])) {
                $expression = $mappings[$expression];
            }
    
            return new static($expression, $fieldFactory ?: new FieldFactory());
        }
    /**
         * Get the next or previous run date of the expression relative to a date
         *
         * @param string|\DateTime $currentTime      Relative calculation date
         * @param int              $nth              Number of matches to skip before returning
         * @param bool             $invert           Set to TRUE to go backwards in time
         * @param bool             $allowCurrentDate Set to TRUE to return the
         *                                           current date if it matches the cron expression
         *
         * @return \DateTime
         * @throws \RuntimeException on too many iterations
         */
        protected function getRunDate($currentTime = null, $nth = 0, $invert = false, $allowCurrentDate = false)
        {
            if ($currentTime instanceof DateTime) {
                $currentDate = clone $currentTime;
            } elseif ($currentTime instanceof DateTimeImmutable) {
                $currentDate = DateTime::createFromFormat('U', $currentTime->format('U'));
                $currentDate->setTimezone($currentTime->getTimezone());
            } else {
                $currentDate = new DateTime($currentTime ?: 'now');
                $currentDate->setTimezone(new DateTimeZone(date_default_timezone_get()));
            }
    
            $currentDate->setTime($currentDate->format('H'), $currentDate->format('i'), 0);
            $nextRun = clone $currentDate;
            $nth = (int) $nth;
    
            // We don't have to satisfy * or null fields
            $parts = array();
            $fields = array();
            foreach (self::$order as $position) {
                $part = $this->getExpression($position);
                if (null === $part || '*' === $part) {
                    continue;
                }
                $parts[$position] = $part;
                $fields[$position] = $this->fieldFactory->getField($position);
            }
    
            // Set a hard limit to bail on an impossible date
            for ($i = 0; $i < $this->maxIterationCount; $i++) {
    
                foreach ($parts as $position => $part) {
                    $satisfied = false;
                    // Get the field object used to validate this part
                    $field = $fields[$position];
                    // Check if this is singular or a list
                    if (strpos($part, ',') === false) {
                        $satisfied = $field->isSatisfiedBy($nextRun, $part);
                    } else {
                        foreach (array_map('trim', explode(',', $part)) as $listPart) {
                            if ($field->isSatisfiedBy($nextRun, $listPart)) {
                                $satisfied = true;
                                break;
                            }
                        }
                    }
    
                    // If the field is not satisfied, then start over
                    if (!$satisfied) {
                        $field->increment($nextRun, $invert, $part);
                        continue 2;
                    }
                }
    
                // Skip this match if needed
                if ((!$allowCurrentDate && $nextRun == $currentDate) || --$nth > -1) {
                    $this->fieldFactory->getField(0)->increment($nextRun, $invert, isset($parts[0]) ? $parts[0] : null);
                    continue;
                }
    
                return $nextRun;
            }
    
            // @codeCoverageIgnoreStart
            throw new RuntimeException('Impossible CRON expression');
            // @codeCoverageIgnoreEnd
        }

    判断需要执行的任务是否是当前任务

    namespace Illuminate\Console\Scheduling;
    
    use Illuminate\Contracts\Cache\Repository as Cache;
    
    class CacheMutex implements Mutex
    {
        /**
         * The cache repository implementation.
         *
         * @var \Illuminate\Contracts\Cache\Repository
         */
        public $cache;
    
        /**
         * Create a new overlapping strategy.
         *
         * @param  \Illuminate\Contracts\Cache\Repository  $cache
         * @return void
         */
        public function __construct(Cache $cache)
        {
            $this->cache = $cache;
        }
    
        /**
         * Attempt to obtain a mutex for the given event.
         *
         * @param  \Illuminate\Console\Scheduling\Event  $event
         * @return bool
         */
        public function create(Event $event)
        {
            return $this->cache->add(
                $event->mutexName(), true, $event->expiresAt
            );
        }
    
        /**
         * Determine if a mutex exists for the given event.
         *
         * @param  \Illuminate\Console\Scheduling\Event  $event
         * @return bool
         */
        public function exists(Event $event)
        {
            return $this->cache->has($event->mutexName());
        }
    
        /**
         * Clear the mutex for the given event.
         *
         * @param  \Illuminate\Console\Scheduling\Event  $event
         * @return void
         */
        public function forget(Event $event)
        {
            $this->cache->forget($event->mutexName());
        }
    }

    互斥 的实现

    protected function expressionPasses()
        {
            $date = Carbon::now();
    
            if ($this->timezone) {
                $date->setTimezone($this->timezone);
            }
    
            return CronExpression::factory($this->expression)->isDue($date->toDateTimeString());
        }

    是否过期

    自己实现一个计划任务

    https://www.cnblogs.com/zx-admin/p/15641124.html

    QQ一群 247823727
    QQ二群 166427999
    博客文件如果不能下载请进群下载
    如果公司项目有技术瓶颈问题,如有需要,技术服务QQ: 903464207
  • 相关阅读:
    解决无法连接mysql问题
    nodejs基础(二)
    JS面试题
    node初学者笔记
    nodejs安装、环境配置和测试
    Linux常用命令笔记
    MangoDb的安装及使用
    Redis安装、命令以及设置密码遇到的问题
    测试端口通不通问题
    发布版本Debug和Release的区别
  • 原文地址:https://www.cnblogs.com/zx-admin/p/9382656.html
Copyright © 2020-2023  润新知