Laravel Queue — 生产和消费

公司的日志系统、推送系统,都是用的Laravel自带的Queue系统,之前只是调用大佬封装好的,不知道实现的原理,今天仔细看了看Queue的源码,总结一下,有不严谨和错误的地方,还希望大佬们指正。

生产

首先我们的业务用的是Beantalked,所以代码查看从BeanstalkdQueue.php的push入队(later方法为延迟队列)方法开始

    /**
	 * Push a new job onto the queue.
	 *
	 * @param  string  $job
	 * @param  mixed   $data
	 * @param  string  $queue
	 * @return mixed
	 */
	public function push($job, $data = '', $queue = null)
	{
		return $this->pushRaw($this->createPayload($job, $data), $queue);
	}

push方法调用自身类中的pushRaw方法,参数为createPayload方法的返回值,createPayload方法序列化job类作为data,job为Illuminate\Queue\CallQueuedHandler@call(若job为为闭包,则为Illuminate\Queue\Illuminate\Queue\Closure)

/**
	 * Create a payload string from the given job and data.
	 *
	 * @param  string  $job
	 * @param  mixed   $data
	 * @param  string  $queue
	 * @return string
	 */
	protected function createPayload($job, $data = '', $queue = null)
	{
		if ($job instanceof Closure)
		{
			return json_encode($this->createClosurePayload($job, $data));
		}
		elseif (is_object($job))
		{
			return json_encode([
				'job' => 'Illuminate\Queue\CallQueuedHandler@call',
				'data' => ['command' => serialize(clone $job)],
			]);
		}

		return json_encode($this->createPlainPayload($job, $data));
	}




	/**
	 * Create a payload string for the given Closure job.
	 *
	 * @param  \Closure  $job
	 * @param  mixed     $data
	 * @return string
	 */
	protected function createClosurePayload($job, $data)
	{
		$closure = $this->crypt->encrypt((new Serializer)->serialize($job));

		return ['job' => 'IlluminateQueueClosure', 'data' => compact('closure')];
	}

    /**
	 * Push a raw payload onto the queue.
	 *
	 * @param  string  $payload
	 * @param  string  $queue
	 * @param  array   $options
	 * @return mixed
	 */
	public function pushRaw($payload, $queue = null, array $options = array())
	{
		return $this->pheanstalk->useTube($this->getQueue($queue))->put(
			$payload, Pheanstalk::DEFAULT_PRIORITY, Pheanstalk::DEFAULT_DELAY, $this->timeToRun
		);
	}

pushRaw方法中调用了pheanstalk的useTube,pheanstalk为Pheanstalk类,该类为PHP实现的beanstalkd的客户端,useTube方法的参数为getQueue方法的返回值,getQueue方法处理若未传入队列名称,则用默认的default队列

    /**
	 * Get the queue or return the default.
	 *
	 * @param  string|null  $queue
	 * @return string
	 */
	public function getQueue($queue)
	{
		return $queue ?: $this->default;
	}

useTube方法设置并选择与队列名相同的tube

     /**
     * {@inheritdoc}
     */
    public function useTube($tube)
    {
        if ($this->_using != $tube) {
            $this->_dispatch(new Command\UseCommand($tube));
            $this->_using = $tube;
        }

        return $this;
    }

入队操作,参数和分别为job数据相关、优先级、延迟时间、有效期

    /**
     * {@inheritdoc}
     */
    public function put(
        $data,
        $priority = PheanstalkInterface::DEFAULT_PRIORITY,
        $delay = PheanstalkInterface::DEFAULT_DELAY,
        $ttr = PheanstalkInterface::DEFAULT_TTR
    )
    {
        $response = $this->_dispatch(
            new Command\PutCommand($data, $priority, $delay, $ttr)
        );

        return $response['id'];
    }

    /**
     * Puts a job on the queue
     * @param string $data     The job data
     * @param int    $priority From 0 (most urgent) to 0xFFFFFFFF (least urgent)
     * @param int    $delay    Seconds to wait before job becomes ready
     * @param int    $ttr      Time To Run: seconds a job can be reserved for
     */
    public function __construct($data, $priority, $delay, $ttr)
    {
        $this->_data = $data;
        $this->_priority = $priority;
        $this->_delay = $delay;
        $this->_ttr = $ttr;
    }

消费

消费时调用CallQueuedHandler类中的call方法,call方法从容器中解析job对应的类,并调用setJobInstanceIfNecessary处理,这里是做判断,自己定义的Job类如果use了InteractsWithQueue特性,则调用该特性的setJob方法,注入Illuminate\Contracts\Queue\Job类,从而使自己定义的Job类可以调用删除、重放等等一系列任务相关操作。

  /**
     * Handle the queued job.
     *
     * @param  \Illuminate\Contracts\Queue\Job  $job
     * @param  array  $data
     * @return void
     */
    public function call(Job $job, array $data)
    {
        try {
            $command = $this->setJobInstanceIfNecessary(
                $job, unserialize($data['command'])
            );
        } catch (ModelNotFoundException $e) {
            return $this->handleModelNotFound($job, $e);
        }

        $this->dispatcher->dispatchNow(
            $command, $this->resolveHandler($job, $command)
        );

        if (! $job->hasFailed() && ! $job->isReleased()) {
            $this->ensureNextJobInChainIsDispatched($command);
        }

        if (! $job->isDeletedOrReleased()) {
            $job->delete();
        }
    }

然后调用call_user_func_array去调用job类中的对应处理方法,第一个参数为数组,元素分别为对应的job和处理method,第二个参数为反序列化后的参数data。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AirGo.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值