没有不值得去解决的问题,也没有不值得去学习的技术!

Deleting Reserved Queues When the Info Command Prints Queue Status in the Yii2 Queue Extension With the Redis Driver

Because Supervisor starts only 1 queue/listen, once a queue is in the reserved state, all other queues must remain in the waiting state. Therefore, I temporarily decided to use the remove command to delete the job in order to resume normal program operation. Checking the message field in the log table confirms the queue ID value is: 159. When the info command prints the queue status information, the number of queues in the reserved state decreases by 1, and the number of queues in the done state increases by 1, as expected

1. Check the log table; its message field contains the following:

Plaintext

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. Analysis reveals that in the event handler for the publish article queue, after the job execution for the publish article queue fails, common\components\queue\PubArticleEventHandler::afterError(ExecEvent $event) throws an exception. Once an exception is thrown, it causes the status of this publish article queue to remain as: reserved. Therefore, you should avoid throwing exceptions in this method whenever possible.

PHP
<?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. In the Yii2 queue extension with the Redis driver, when the info command prints information about the queue status, the number of queues in the reserved state is 33, as shown in Figure 1.

In the Yii2 queue extension with the Redis driver, when the info command prints information about the queue status, the number of queues in the reserved state is 33
Figure 1
Plaintext

[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. Because Supervisor starts only 1 queue/listen, once a queue is in the reserved state, all other queues must remain in the waiting state. Therefore, I temporarily decided to use the remove command to delete the job in order to resume normal program operation. Checking the message field in the log table confirms the queue ID value is: 159. When the info command prints the queue status information, the number of queues in the reserved state decreases by 1, and the number of queues in the done state increases by 1, as expected, as shown in Figure 2.

Because Supervisor starts only 1 queue/listen, once a queue is in the reserved state, all other queues must remain in the waiting state. Therefore, I temporarily decided to use the remove command to delete the job in order to resume normal program operation. Checking the message field in the log table confirms the queue ID value is: 159. When the info command prints the queue status information, the number of queues in the reserved state decreases by 1, and the number of queues in the done state increases by 1, as expected
Figure 2
Plaintext

[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. Based on the above process, I repeatedly executed the remove command to delete jobs. After waiting for a while, when the info command prints the queue status information, the number of queues in the reserved state continues to decrease, and the number of queues in the done state continues to increase, as expected.

Plaintext

[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

关于作者 · 持续学习与技术实践

我是一名拥有 15 年以上开发经验的技术从业者,自 2013 年起持续运营个人技术博客,记录工作与个人项目中遇到的真实问题,以及解决问题过程中的探索、实践和思考。

除了技术写作,我也在持续开发和维护自己的独立项目,探索新技术和新工具在实际场景中的应用。我始终相信,没有不值得去解决的问题,也没有不值得去学习的技术。

如果这篇文章对你有所帮助,欢迎浏览博客中的其他文章,也欢迎交流技术经验与想法。

关于我  ·  GitHub  ·  邮件联系