Yii2 队列扩展,Redis 驱动中,info 命令打印关于队列状态的信息时,reserved 状态的队列的删除

1、查看 log 表,其 message 字段内容如下:

yii\web\NotFoundHttpException: The task ID of the channel's article: 2209, does not exist in /mcloud/www/channel-pub-api/common/components/queue/PubArticleEventHandler.php:93
Stack trace:
#0 [internal function]: common\components\queue\PubArticleEventHandler::afterError(Object(yii\queue\ErrorEvent))
#1 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2/base/Component.php(627): call_user_func(Array, Object(yii\queue\ErrorEvent))
#2 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2-queue/src/Queue.php(246): yii\base\Component->trigger('afterError', Object(yii\queue\ErrorEvent))
#3 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2-queue/src/cli/Command.php(198): yii\queue\Queue->handleError('159', Object(wx\jobs\PubArticleJob), '300', '1085', Object(Symfony\Component\Process\Exception\ProcessFailedException))
#4 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2-queue/src/cli/Command.php(125): yii\queue\cli\Command->handleMessage('159', 'O:21:"wx\\jobs\\P...', '300', '1085')
#5 [internal function]: yii\queue\cli\Command->yii\queue\cli\{closure}('159', 'O:21:"wx\\jobs\\P...', '300', '1085')
#6 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2-queue/src/cli/Queue.php(144): call_user_func(Object(Closure), '159', 'O:21:"wx\\jobs\\P...', '300', '1085')
#7 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2-queue/src/drivers/redis/Queue.php(61): yii\queue\cli\Queue->handleMessage('159', 'O:21:"wx\\jobs\\P...', '300', '1085')
#8 [internal function]: yii\queue\redis\Queue->yii\queue\redis\{closure}(Object(Closure))
#9 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2-queue/src/cli/Queue.php(117): call_user_func(Object(Closure), Object(Closure))
#10 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2-queue/src/drivers/redis/Queue.php(68): yii\queue\cli\Queue->runWorker(Object(Closure))
#11 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2-queue/src/drivers/redis/Command.php(76): yii\queue\redis\Queue->run(true, 3)
#12 [internal function]: yii\queue\redis\Command->actionListen(3)
#13 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)
#14 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2/base/Controller.php(157): yii\base\InlineAction->runWithParams(Array)
#15 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2/console/Controller.php(148): yii\base\Controller->runAction('listen', Array)
#16 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2/base/Module.php(528): yii\console\Controller->runAction('listen', Array)
#17 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2/console/Application.php(180): yii\base\Module->runAction('pub-article-que...', Array)
#18 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2/console/Application.php(147): yii\console\Application->runAction('pub-article-que...', Array)
#19 /mcloud/www/channel-pub-api/vendor/yiisoft/yii2/base/Application.php(386): yii\console\Application->handleRequest(Object(yii\console\Request))
#20 /mcloud/www/channel-pub-api/yii(23): yii\base\Application->run()
#21 {main}

2、分析发现,发布文章队列事件处理器,发布文章队列的作业执行失败后,common\components\queue\PubArticleEventHandler::afterError(ExecEvent $event),在此方法中抛出异常,一旦抛出异常,进而便会导致此发布文章队列的状态一直处于:reserved,因此,应该尽可能避免在此方法中抛出异常

<?php
/**
 * Created by PhpStorm.
 * User: Qiang Wang
 * Date: 2018/10/23
 * Time: 19:36
 */
namespace common\components\queue;

use Yii;
use common\services\TaskService;
use common\services\ChannelAppTaskService;
use common\services\ArticleTypeService;
use yii\base\Component;
use yii\queue\ExecEvent;
use yii\web\NotFoundHttpException;
use yii\web\UnprocessableEntityHttpException;

/**
 * Class PubArticleEventHandler
 * @package common\components\queue
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */class PubArticleEventHandler extends Component
{
    /**
     * @param ExecEvent $event
     * @throws NotFoundHttpException 如果未找到数据模型,将抛出 404 HTTP 异常
     * @throws UnprocessableEntityHttpException 如果找到数据模型,状态未启用,将抛出 422 HTTP 异常
     */    public static function afterExec(ExecEvent $event)
    {
        $channelAppTaskId = $event->job->channelAppTaskId;

        // 基于ID查找状态为未禁用的单个数据模型(渠道的应用的任务)
        $channelAppTaskDisabledNoItem = ChannelAppTaskService::findModelDisabledNoById($channelAppTaskId);

        // 基于ID查找状态为启用的单个数据模型(任务)
        $taskEnabledItem = TaskService::findModelEnabledById($channelAppTaskDisabledNoItem->task_id);

        $serviceClass = 'common\services\\' . str_replace(' ', '', ucwords(str_replace('_', ' ', $taskEnabledItem->channel_type_code))) . 'ArticleService'; // 例:common\services\QqCwArticleService

        $articleModel = 'common\logics\\' . str_replace(' ', '', ucwords(str_replace('_', ' ', $taskEnabledItem->channel_code))) . 'Article'; // 例:common\logics\QqArticle

        // 基于任务ID查找单个数据模型(渠道的文章)
        $articleModelItem = $articleModel::find()->where(['task_id' => $taskEnabledItem->id])->isDeletedNo()->one();

        // 如果未找到数据模型,将抛出 404 HTTP 异常
        if (!isset($articleModelItem)) {
            throw new NotFoundHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '202091'), ['task_id' => $taskEnabledItem->id])), 202091);
        }

        /* 判断状态,如果未启用,将抛出 422 HTTP 异常 */        if ($articleModelItem->status !== $articleModelItem::STATUS_ENABLED) {
            throw new UnprocessableEntityHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '202092'), ['task_id' => $taskEnabledItem->id])), 202092);
        }

        // 基于ID查找状态为启用的单个数据模型(文章类型)
        $articleTypeEnabledItem = ArticleTypeService::findModelEnabledById($articleModelItem->article_type_id);

        $serviceAction = 'pubArticle' . str_replace(' ', '', ucwords(str_replace('_', ' ', $articleTypeEnabledItem->code))) . 'ExecHandler'; // 例:pubArticleVideoExecHandler

        $serviceClass::$serviceAction($channelAppTaskId);
    }

    /**
     * @param ExecEvent $event
     * @throws NotFoundHttpException 如果未找到数据模型,将抛出 404 HTTP 异常
     * @throws UnprocessableEntityHttpException 如果找到数据模型,状态未启用,将抛出 422 HTTP 异常
     */    public static function afterError(ExecEvent $event)
    {
        $channelAppTaskId = $event->job->channelAppTaskId;

        // 基于ID查找状态为未禁用的单个数据模型(渠道的应用的任务)
        $channelAppTaskDisabledNoItem = ChannelAppTaskService::findModelDisabledNoById($channelAppTaskId);

        // 基于ID查找状态为启用的单个数据模型(任务)
        $taskEnabledItem = TaskService::findModelEnabledById($channelAppTaskDisabledNoItem->task_id);

        $serviceClass = 'common\services\\' . str_replace(' ', '', ucwords(str_replace('_', ' ', $taskEnabledItem->channel_type_code))) . 'ArticleService'; // 例:common\services\QqCwArticleService

        $articleModel = 'common\logics\\' . str_replace(' ', '', ucwords(str_replace('_', ' ', $taskEnabledItem->channel_code))) . 'Article'; // 例:common\logics\QqArticle

        // 基于任务ID查找单个数据模型(渠道的文章)
        $articleModelItem = $articleModel::find()->where(['task_id' => $taskEnabledItem->id])->isDeletedNo()->one();

        // 如果未找到数据模型,将抛出 404 HTTP 异常
        if (!isset($articleModelItem)) {
            throw new NotFoundHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '202091'), ['task_id' => $taskEnabledItem->id])), 202091);
        }

        /* 判断状态,如果未启用,将抛出 422 HTTP 异常 */        if ($articleModelItem->status !== $articleModelItem::STATUS_ENABLED) {
            throw new UnprocessableEntityHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '202092'), ['task_id' => $taskEnabledItem->id])), 202092);
        }

        // 基于ID查找状态为启用的单个数据模型(文章类型)
        $articleTypeEnabledItem = ArticleTypeService::findModelEnabledById($articleModelItem->article_type_id);

        $serviceAction = 'pubArticle' . str_replace(' ', '', ucwords(str_replace('_', ' ', $articleTypeEnabledItem->code))) . 'ErrorHandler'; // 例:pubArticleVideoErrorHandler

        $serviceClass::$serviceAction($channelAppTaskId, $event->error);
    }
}

3、Yii2 队列扩展,Redis 驱动中,info 命令打印关于队列状态的信息时,reserved 状态的队列数量为 33,如图1

图1

[root@cc121bb54862 /]# cd /mcloud/www/channel-pub-api/
[root@cc121bb54862 channel-pub-api]# ./yii copy-asset-queue/info --color=0
Jobs
- waiting: 0
- delayed: 0
- reserved: 0
- done: 146
[root@cc121bb54862 channel-pub-api]# ./yii upload-asset-queue/info --color=0
Jobs
- waiting: 0
- delayed: 0
- reserved: 0
- done: 0
[root@cc121bb54862 channel-pub-api]# ./yii pub-article-queue/info --color=0
Jobs
- waiting: 20
- delayed: 0
- reserved: 33
- done: 162
[root@cc121bb54862 channel-pub-api]# ./yii source-callback-queue/info --color=0
Jobs
- waiting: 0
- delayed: 0
- reserved: 0
- done: 166

4、由于 Supervisor 仅启动 1 个 queue/listen,因此,一旦某一队列处于 reserved,则其他队列只好一直处于 waiting 状态,所以,临时决定 remove 命令删除作业,以启动程序的继续正常运转,查看 log 表,其 message 字段内容,可以确定队列 ID 值为:159,info 命令打印关于队列状态的信息时,reserved 状态的队列数量减少 1,done 状态的队列数量增加 1,符合预期,如图2

图2

[root@cc121bb54862 /]# cd /mcloud/www/channel-pub-api/
[root@cc121bb54862 channel-pub-api]# ./yii pub-article-queue/info --color=0
Jobs
- waiting: 20
- delayed: 0
- reserved: 33
- done: 162
[root@cc121bb54862 channel-pub-api]# ./yii pub-article-queue/remove 159
[root@cc121bb54862 channel-pub-api]# ./yii pub-article-queue/info --color=0
Jobs
- waiting: 20
- delayed: 0
- reserved: 32
- done: 163

5、基于以上流程,重复地分别执行 remove 命令删除作业,等待一段时间后,info 命令打印关于队列状态的信息时,reserved 状态的队列数量持续减少中,done 状态的队列数量持续增加中,符合预期

[root@cc121bb54862 /]# cd /mcloud/www/channel-pub-api/
[root@cc121bb54862 channel-pub-api]# ./yii pub-article-queue/info --color=0
Jobs
- waiting: 18
- delayed: 0
- reserved: 33
- done: 164
[root@cc121bb54862 channel-pub-api]# ./yii pub-article-queue/remove 184
[root@cc121bb54862 channel-pub-api]# ./yii pub-article-queue/info --color=0
Jobs
- waiting: 17
- delayed: 0
- reserved: 33
- done: 165
[root@cc121bb54862 channel-pub-api]# ./yii pub-article-queue/remove 175
[root@cc121bb54862 channel-pub-api]# ./yii pub-article-queue/info --color=0
Jobs
- waiting: 18
- delayed: 0
- reserved: 30
- done: 167
[root@cc121bb54862 channel-pub-api]# ./yii pub-article-queue/remove 141
[root@cc121bb54862 channel-pub-api]# ./yii pub-article-queue/info --color=0
Jobs
- waiting: 18
- delayed: 0
- reserved: 29
- done: 168
[root@cc121bb54862 channel-pub-api]# ./yii pub-article-queue/remove 168
[root@cc121bb54862 channel-pub-api]# ./yii pub-article-queue/info --color=0
Jobs
- waiting: 17
- delayed: 0
- reserved: 29
- done: 169

 

永夜