In Yii2 advanced template, the task is implemented asynchronously based on the Yii2 queue extension, and the additional event handler is attached, after each successful execution of the job, when an exception occurs during the job execution.
1. By configuring the additional event processor, edit \environments\dev\common\config\main-local.php, \environments\prod\common\config\main-local.php, as shown in Figure 1

<br> CopyAssetQueue=>[ // 复制资源文件队列<br> class=>Yii\Queue\Redis\Queue,<br> redis=>redis, // Redis connection component or its configuration<br> channel=>cpa:queue:copy:asset, // Queue key prefix<br> TTR=> 10 * 60, // Maximum time for job processing, in (seconds)<br> on afterexec=> [common\components\queue\copyAssetEventHandler,AfterExec]#atfp_close_translate_span#, // after each successful job execution<br> on afterError=>['common\components\queue\CopyAssetEventHandler', 'afterError'], // when an uncaught exception occurs during the job execution<br> as log=>yii\queue\logbehavior,<br> ],<br> UploadAssetQueue=>[ // 上传资源文件队列<br> class=>Yii\Queue\Redis\Queue,<br> redis=>redis, // Redis connection component or its configuration<br> channel=>cpa:queue:upload:asset, // Queue key prefix<br> TTR=> 5 * 60, // Maximum time for job processing, in (seconds)<br> on afterexec=> [Common\Components\Queue\UploadAssetEventHandler,AfterExec]#atfp_close_translate_span#, // after each successful job execution<br> on afterError=>['common\components\queue\UploadAssetEventHandler', 'afterError'], // when an uncaught exception occurs during the job execution<br> as log=>yii\queue\logbehavior,<br> ],<br> PubArticleQueue=>[ // 发布文章队列<br> class=>Yii\Queue\Redis\Queue,<br> redis=>redis, // Redis connection component or its configuration<br> channel=>cpa:queue:pub:article, // Queue key prefix<br> TTR=> 5 * 60, // Maximum time for job processing, in (seconds)<br> on afterexec=> [Common\Components\Queue\PubarticleEventHandler,AfterExec]#atfp_close_translate_span#, // after each successful job execution<br> on afterError=>['common\components\queue\PubArticleEventHandler', 'afterError'], // when an uncaught exception occurs during the job execution<br> as log=>yii\queue\logbehavior,<br> ],<br> SourceCallbackQueue=>[ // 来源回调队列<br> class=>Yii\Queue\Redis\Queue,<br> redis=>redis, // Redis connection component or its configuration<br> channel=>cpa:queue:source:callback, // Queue key prefix<br> TTR=> 5 * 60, // Maximum time for job processing, in (seconds)<br> on afterexec=> [Common\Components\Queue\SourceCallbackBackEventHandler,AfterExec]#atfp_close_translate_span#, // after each successful job execution<br> on afterError=>['common\components\queue\SourceCallbackEventHandler', 'afterError'], // when an uncaught exception occurs during the job execution<br> as log=>yii\queue\logbehavior,<br> ],<br>
2. Edit \QQ\RESTS\QQ_CW_APP\IndexAction.php, an entry of a push queue
<br> $data =[<br> channel_id=> 2, // Channel ID<br> channel_code=>wx, // Channel code, QQ: Penguin number; WX: WeChat public account<br> channel_type_id=> 3, // Type ID of the channel<br> channel_type_code=>wx, // Type code of the channel, QQ_CW: the content website application of the Penguin account; QQ_TP: the third-party service platform application of the Penguin account; WX: the WeChat public account application<br> Source=>spider, // Source, Xcontent: content library; VMS: video management system; CMS: content management system; spider: self-media<br> task_id=> 2, // Task ID<br> ]#atfp_close_translate_span#;<br> $assets =[<br> [<br> type=>image,<br> channel_article_id=> 1,<br> ABSOLUTE_URL=>http://localhost/channel-pub-api/storage/spider/images/1.png,<br> ]#ATFP_CLOSE_Translate_span#,<br> [<br> type=>video,<br> channel_article_id=> 1,<br> ABSOLUTE_URL=>http://localhost/channel-pub-api/storage/spider/videos/In July, the rents of the top ten cities including Beijing, Shanghai, Guangzhou and Shenzhen rose on a month-on-month increase. Look at Dongfang 20180820 HD_HD.mp4,<br> ]#ATFP_CLOSE_Translate_span#,<br> ];<br> $AssetServiceCopyAssetSasyncResult = AssetService::CopyAssetSasync($data, $Assets);<br> print_r($AssetServiceCopyAssetsAsyncResult);<br> exit;<br>
3. Edit \Common\Services\AssetService.php, copy the source resource file to the resource directory published by the channel, after the queue task is successfully executed, call the corresponding service, otherwise, insert the release log (asynchronous)
<br>
/**<br>
* Copy the source resource file to the resource directory published by the channel. After the queue task is successfully executed, call the corresponding service, otherwise, insert the release log (asynchronous)<br>
* @param array $data<br>
* The format is as follows:<br>
;[<br>
;channel_id=> 1, // Channel ID<br>
;channel_code=>qq, // Channel code, QQ: Penguin number; WX: WeChat public account<br>
;channel_type_id=> 1, // Type ID of the channel<br>
;channel_type_code=>qq_cw, // Type code of the channel, QQ_CW: the content website application of the Penguin account; QQ_TP: the third-party service platform application of the Penguin account; WX: the WeChat public account application<br>
;Source=>spider, // Source, Xcontent: content library; VMS: video management system; CMS: content management system; spider: self-media<br>
;task_id=> 1, // Task ID<br>
* ]#atfp_close_translate_span#<br>
;<br>
* @param array $assets the absolute url of the resource file from the source<br>
* The format is as follows:<br>
;[<br>
* [<br>
;type=>image, // Type of resource file, image: image; video: video<br>
;channel_article_id=> 1, // The article ID of the channel<br>
;ABSOLUTE_URL=>http://localhost/spider/storage/spider/images/1.png, // The absolute URL of the source file of the source<br>
* ]#atfp_close_translate_span#,<br>
;[<br>
;type=>video, // Type of resource file, image: image; video: video<br>
;channel_article_id=> 1, // The article ID of the channel<br>
;ABSOLUTE_URL=>http://localhost/channel-pub-api/storage/spider/videos/In July, the rents of the top ten cities including Beijing, Shanghai, Guangzhou and Shenzhen rose on a month-on-month increase. Look at Dongfang 20180820 HD_HD.mp4, // The absolute URL of the source file of the source<br>
* ]#atfp_close_translate_span#,<br>
* ]<br>
;<br>
* @Return Array $ChannelPabApiAsSetAbsolutePaths Relative path of resource files published by the channel<br>
* The format is as follows:<br>
;[<br>
* [<br>
;type=>image,<br>
;channel_article_id=> 1,<br>
;relative_path=>/2018/09/20/1537439889.2333.1441541478.png,<br>
* ]#atfp_close_translate_span#,<br>
;[<br>
;type=>video,<br>
;channel_article_id=> 1,<br>
;relative_path=>/2018/09/20/1537439889.2403.62871268.mp4,<br>
* ]#atfp_close_translate_span#,<br>
* ]<br>
;<br>
* @throws exception execution failed<br>
*/<br>
public static function CopyAssetsAsync($data, $assets)<br>
{<br>
$assetdata =[];<br>
$time = time();<br>
foreach ($assets as $key => $asset) {<br>
$assetdata[]=[<br>
channel_id=> $data[channel_id]#ATFP_CLOSE_Translate_span#,<br>
channel_code=> $data['channel_code'],<br>
channel_type_id=> $data['channel_type_id'],<br>
channel_type_code=> $data['channel_type_code'],<br>
Source=> $data['source'],<br>
type=> $asset['type'],<br>
ABSOLUTE_URL=> $asset['absolute_url'],<br>
relative_path=>,<br>
Size=> 0,<br>
task_id=> $data['task_id'],<br>
channel_article_id=> $asset['channel_article_id'],<br>
status=>asset::status_enabled,<br>
is_deleted=>asset::is_deleted_no,<br>
created_at=> $time,<br>
updated_at=> $time,<br>
deleted_at=>asset::deleted_at_default,<br>
];<br>
}</p>
<p> // Create resources in batches<br>
$asset = new asset();<br>
$AssetCreateMultipleResult = $Asset->CreateMultiple($AssetData);</p>
<p> // Send the task to the queue (copy the resource file queue) and process it through the standard staff<br>
yii::$app->CopyAssetQueue->Push(New CopyAssetJob([<br>
TaskId=> $data[task_id]#ATFP_CLOSE_Translate_span#,<br>
]));<br>
}<br>
4. Edit \Common\Jobs\CopyAssetJob.php, the task class of the queue
<br>
<?php<br>
/**<br>
* Created by phpstorm.<br>
* user: qiang wang<br>
* Date: 2018/10/22<br>
* Time: 17:10<br>
*/</p>
<p>namespace common\jobs;</p>
<p>use yii;<br>
use common\logics\asset;<br>
use common\services\taskservice;<br>
use common\services\AssetService;<br>
Use Yii\Web\ServerErrorHttpException;</p>
<p>/**<br>
* Copy the source resource file to the resource directory published by the channel<br>
;<br>
* @author qiang wang <shuijingwanwq@163.com><br>
* @since 1.0<br>
*/<br>
Class CopyAssetJob extends job<br>
{<br>
public $taskid;</p>
<p> tiveting<br>
* @Throws ServerErrorHttpException throws a 500 HTTP exception if the list of resources enabled based on the task ID is empty<br>
*/<br>
public function execute($queue)<br>
{<br>
// Find a single data model enabled based on ID (task)<br>
$taskenabledItem = TaskService::FindModeLeNabledById($this->taskId);</p>
<p> // Find the list of resources enabled based on the task ID<br>
$AssetEnableDItems = asset::findAllEnabledByTaskiId($this->taskId);</p>
<p> if (empty($AssetEnabledItems)) {<br>
Throw new ServerErrorHttpException(yii::t(common/error, yii::t(common/error, yii::t(common/error,35020,['task_id' => $this->taskId])), 35020);<br>
}</p>
<p> $source = $taskenabledItem->source;<br>
$assets =[];<br>
foreach ($AssetEnabledItems as $AssetEnabledItem) {<br>
$assets[]=[<br>
type=> $AssetEnabledItem->Type,<br>
ABSOLUTE_URL=> $AssetEnabledItem->ABSOLUTE_URL,<br>
]#atfp_close_translate_span#;<br>
}</p>
<p> // Copy the resource file of the source to the resource directory published by the channel, and return the relative path (sync)<br>
$AssetServiceCopyAssetSynCresult = AssetService::CopyAssetSync($Source, $Assets);<br>
foreach ($AssetEnableDItems as $KEY => $AssetEnabledItem) {<br>
$AssetEnabledItem->relative_path = $AssetServiceCopyAssetSynCresult[$key]['relative_path'];<br>
// get file size, unit (byte)<br>
$AssetEnabledItem->size = fileSize(yii::$app->params['channelPubApi']['asset'][$assetEnabledItem->type]['basePath']. $AssetServiceCopyAssetsSyncResult[$key]['relative_path']);<br>
$AssetEnableDItems[$key]= $AssetEnabledItem;<br>
}</p>
<p> // update resources in batches<br>
$AssetEnableDItem->UpdateMultiple($AssetEnableDItems);<br>
}<br>
}<br>
5. Edit \common\components\queue\copyAssetEventHandler.php, the event handler defined in the configuration, when the resource file queue is copied, after each successful execution of the job (Aftere) XEC), the corresponding service will be called for subsequent processing, that is, the task is pushed to the upload resource file queue; when the resource file queue is copied, When an uncaught exception occurs during business execution, insert a release log and push the job to the source callback queue
<br>
<?php<br>
/**<br>
* Created by phpstorm.<br>
* user: qiang wang<br>
* Date: 2018/10/23<br>
* time: 14:23<br>
*/</p>
<p>namespace common\components\queue;</p>
<p>use yii;<br>
use common\logics\channelapptask;<br>
use common\logics\publog;<br>
use common\services\publogservice;<br>
use common\services\taskservice;<br>
use common\services\sourceCallbackService;<br>
use yii\helpers\json;<br>
use yii\base\component;<br>
use yii\queue\execEvent;<br>
use yii\web\NotFoundHttpException;<br>
use yii\web\unprocessableEntityHttpException;<br>
Use Yii\Web\ServerErrorHttpException;<br>
use yii\db\exception;</p>
<p>/**<br>
* Class CopyAssetEventHandler<br>
* @package common\components\queue<br>
;<br>
* @author qiang wang <shuijingwanwq@163.com><br>
* @since 1.0<br>
*/<br>
Class CopyAssetEventHandler extends component<br>
{<br>
/**<br>
* @param execEvent $event<br>
* @Throws NotFoundHttpException throws 404 HTTP exception if no data model is found<br>
* @throws unprocessableEntityHttpException throws 422 HTTP exception if the data model is found<br>
* @Throws ServerErrorHttpException throws a 500 HTTP exception if the list of resources enabled based on the task ID is empty<br>
* @throws exception execution failed<br>
*/<br>
public static function afterExec(execEvent $event)<br>
{<br>
$taskid = $event->job->taskId;<br>
// Find a single data model enabled based on ID (task)<br>
$taskenabledItem = TaskService::FindModeLeNabledById($taskid);</p>
<p> // Find the list of resources enabled based on the task ID<br>
$ChannelAppTaskenableDItems = ChannelAppTask::FindAllEnabledByTaskid($taskId);</p>
<p> if (empty($ChannelAppTaskenabledItems)) {<br>
Throw new ServerErrorHttpException(yii::t(common/error, yii::t(common/error, yii::t(common/error,35021,['task_id' => $taskId])), 35021);<br>
}</p>
<p> try {<br>
// call the corresponding service for subsequent processing<br>
$serviceClass =common\services\\. str_replace(,, ucwords(str_replace(_,, $taskenabledItem->channel_type_code))) .AssetService; // Example: Common\Services\QQCWAssetService<br>
$serviceAction =CopyAssetTexeChandler;<br>
$serviceClass::$serviceAction($taskenabledItem->id);<br>
} catch (\throwable $E) {<br>
$publogdata =[];<br>
$time = time();<br>
foreach ($ChannelAppTaskenabledItems as $ChannelAppTaskenabledItem) {<br>
$publogdata[]=[<br>
channel_id=> $ChannelAppTaskenabledItem[channel_id]#ATFP_CLOSE_Translate_span#,<br>
channel_code=> $ChannelAppTaskenabledItem['channel_code'],<br>
channel_type_id=> $ChannelAppTaskenabledItem['channel_type_id'],<br>
channel_type_code=> $ChannelAppTaskenabledItem['channel_type_code'],<br>
task_id=> $ChannelAppTaskenabledItem['task_id'],<br>
channel_app_task_id=> $ChannelAppTaskenabledItem['id'],<br>
channel_app_task_uuid=> $ChannelAppTaskenabledItem['uuid'],<br>
code=> $e->getCode(),<br>
Message=> $e->getMessage(),<br>
data=> json::encode([],<br>
status=> publog::status_error,<br>
is_deleted=> publog::is_deleted_no,<br>
created_at=> $time,<br>
updated_at=> $time,<br>
deleted_at=> publog::deleted_at_default,<br>
];<br>
}</p>
<p> // After the post task is successful, the call to the corresponding service fails, insert the release log, and push the job to the source callback queue (asynchronous)<br>
SourceCallbackService::erroRasync($publogData);<br>
}<br>
}</p>
<p> /**<br>
* @param execEvent $event<br>
* @Throws NotFoundHttpException throws 404 HTTP exception if no data model is found<br>
* @throws unprocessableEntityHttpException throws 422 HTTP exception if the data model is found<br>
* @Throws ServerErrorHttpException throws a 500 HTTP exception if the list of resources enabled based on the task ID is empty<br>
* @throws exception execution failed<br>
*/<br>
public static function afterError(execEvent $event)<br>
{<br>
$taskid = $event->job->taskId;<br>
// Find a single data model enabled based on ID (task)<br>
$taskenabledItem = TaskService::FindModeLeNabledById($taskid);</p>
<p> // Find the list of resources enabled based on the task ID<br>
$ChannelAppTaskenableDItems = ChannelAppTask::FindAllEnabledByTaskid($taskId);</p>
<p> if (empty($ChannelAppTaskenabledItems)) {<br>
Throw new ServerErrorHttpException(yii::t(common/error, yii::t(common/error, yii::t(common/error,35021,['task_id' => $taskId])), 35021);<br>
}</p>
<p> $publogdata =[];<br>
$time = time();<br>
foreach ($ChannelAppTaskenabledItems as $ChannelAppTaskenabledItem) {<br>
$publogdata[]=[<br>
channel_id=> $ChannelAppTaskenabledItem[channel_id]#ATFP_CLOSE_Translate_span#,<br>
channel_code=> $ChannelAppTaskenabledItem['channel_code'],<br>
channel_type_id=> $ChannelAppTaskenabledItem['channel_type_id'],<br>
channel_type_code=> $ChannelAppTaskenabledItem['channel_type_code'],<br>
task_id=> $ChannelAppTaskenabledItem['task_id'],<br>
channel_app_task_id=> $ChannelAppTaskenabledItem['id'],<br>
channel_app_task_uuid=> $ChannelAppTaskenabledItem['uuid'],<br>
code=> $event->Error->getCode(),<br>
Message=> $event->Error->getMessage(),<br>
data=> json::encode([],<br>
status=> publog::status_error,<br>
is_deleted=> publog::is_deleted_no,<br>
created_at=> $time,<br>
updated_at=> $time,<br>
deleted_at=> publog::deleted_at_default,<br>
];<br>
}</p>
<p> // After the publishing task fails, insert the release log and push the job to the source callback queue (asynchronous)<br>
SourceCallbackService::erroRasync($publogData);<br>
}<br>
}<br>
6. Open the URL: http://api.channel-pub-api.localhost/qq/v1/qq-cw-apps?group_id=spider , push the task to the queue
7. The info command prints the information about the queue status, copying the status of 1 task in the resource file queue is waiting, and uploading the 0 task status in the resource file queue is waiting
<br> .\yii copy-asset-queue/info --color=0<br> .\yii upload-asset-queue/info --color=0<br>
<br> jobs<br> - Waiting: 1<br> - delayed: 0<br> - reserved: 0<br> - done: 0</p> <p>jobs<br> - Waiting: 0<br> - delayed: 0<br> - reserved: 0<br> - done: 0<br>
8. Run The command obtains and executes the tasks in the loop (copy the resource file queue), until the queue is empty, after the task in the resource file queue is successfully executed, the next upload task is pushed to the upload resource File queue, copy the 0 task status in the resource file queue is waiting, the copy of the resource file queue is complete, and the upload resource file queue is waiting, as shown in Figure 2

<br> .\yii copy-asset-queue/run --verbose=1 --isolate=1 --color=0<br> .\yii copy-asset-queue/info<br> .\yii upload-asset-queue/info --color=0<br>
<br> 2018-10-27 17:23:54[pid: 5216]- Worker is started<br> 2018-10-27 17:23:54[1]Common\Jobs\CopyAssetJob (attempt: 1, PID: 5216) - Started<br> 2018-10-27 17:23:55[1]Common\Jobs\CopyAssetJob (attempt: 1, PID: 5216) - Done (0.249 S)<br> 2018-10-27 17:23:55[pid: 5216]- Worker is stopped (0:00:01)</p> <p>jobs<br> - Waiting: 0<br> - delayed: 0<br> - reserved: 0<br> - done: 1</p> <p>jobs<br> - Waiting: 1<br> - delayed: 0<br> - reserved: 0<br> - done: 0<br>
9. Edit \common\jobs\copyAssetJob.php, the task class of the queue, specially throw an exception to test when the data is copied The source file queue, when an uncaught exception occurs during the job execution (AfterError), inserts the release log, and pushes the job to the source callback queue
<br>
<?php<br>
/**<br>
* Created by phpstorm.<br>
* user: qiang wang<br>
* Date: 2018/10/22<br>
* Time: 17:10<br>
*/</p>
<p>namespace common\jobs;</p>
<p>use yii;<br>
use common\logics\asset;<br>
use common\services\taskservice;<br>
use common\services\AssetService;<br>
Use Yii\Web\ServerErrorHttpException;</p>
<p>/**<br>
* Copy the source resource file to the resource directory published by the channel<br>
;<br>
* @author qiang wang <shuijingwanwq@163.com><br>
* @since 1.0<br>
*/<br>
Class CopyAssetJob extends job<br>
{<br>
public $taskid;</p>
<p> tiveting<br>
* @Throws ServerErrorHttpException throws a 500 HTTP exception if the list of resources enabled based on the task ID is empty<br>
*/<br>
public function execute($queue)<br>
{<br>
// Find a single data model enabled based on ID (task)<br>
$taskenabledItem = TaskService::FindModeLeNabledById($this->taskId);</p>
<p> // Find the list of resources enabled based on the task ID<br>
$AssetEnableDItems = asset::findAllEnabledByTaskiId($this->taskId);</p>
<p> Throw new ServerErrorHttpException(yii::t(common/error, yii::t(common/error, yii::t(common/error,35020,['task_id' => $this->taskId])), 35020);<br>
if (empty($AssetEnabledItems)) {<br>
Throw new ServerErrorHttpException(yii::t(common/error, yii::t(common/error, yii::t(common/error,35020,['task_id' => $this->taskId])), 35020);<br>
}</p>
<p> $source = $taskenabledItem->source;<br>
$assets =[];<br>
foreach ($AssetEnabledItems as $AssetEnabledItem) {<br>
$assets[]=[<br>
type=> $AssetEnabledItem->Type,<br>
ABSOLUTE_URL=> $AssetEnabledItem->ABSOLUTE_URL,<br>
]#atfp_close_translate_span#;<br>
}</p>
<p> // Copy the resource file of the source to the resource directory published by the channel, and return the relative path (sync)<br>
$AssetServiceCopyAssetSynCresult = AssetService::CopyAssetSync($Source, $Assets);<br>
foreach ($AssetEnableDItems as $KEY => $AssetEnabledItem) {<br>
$AssetEnabledItem->relative_path = $AssetServiceCopyAssetSynCresult[$key]['relative_path'];<br>
// get file size, unit (byte)<br>
$AssetEnabledItem->size = fileSize(yii::$app->params['channelPubApi']['asset'][$assetEnabledItem->type]['basePath']. $AssetServiceCopyAssetsSyncResult[$key]['relative_path']);<br>
$AssetEnableDItems[$key]= $AssetEnabledItem;<br>
}</p>
<p> // update resources in batches<br>
$AssetEnableDItem->UpdateMultiple($AssetEnableDItems);<br>
}<br>
}<br>
10. Empty Redis, that is, clear the data in the queue, open the URL: http://api.channel-pub-api.localhost/qq/v1/qq-cw-apps?group_id=spider , push the task to the queue
11. The info command prints information about the queue status, copying the status of 1 task in the resource file queue is waiting, 0 task states in the upload resource file queue is waiting, and 0 task states in the source callback queue are waiting
<br> .\yii copy-asset-queue/info --color=0<br> .\yii upload-asset-queue/info --color=0<br> .\yii source-callback-queue/info --color=0<br>
<br> jobs<br> - Waiting: 1<br> - delayed: 0<br> - reserved: 0<br> - done: 0</p> <p>jobs<br> - Waiting: 0<br> - delayed: 0<br> - reserved: 0<br> - done: 0</p> <p>jobs<br> - Waiting: 0<br> - delayed: 0<br> - reserved: 0<br> - done: 0<br>
12. Run The command fetches and executes the tasks in the loop (copy the resource file queue) until the queue is empty, and the task in the resource file queue fails to execute (because there is an uncaught exception in the task), and the next upload task is pushed to the upload resource File queue, copy the 0 task status in the resource file queue is waiting, copy the resource file queue 1 task status is complete, upload 0 task status in the uploaded resource file queue is waiting, and 1 task status in the source callback queue is waiting, as shown in Figure 3

<br> .\yii copy-asset-queue/run --verbose=1 --isolate=1 --color=0<br> .\yii copy-asset-queue/info --color=0<br> .\yii upload-asset-queue/info --color=0<br> .\yii source-callback-queue/info --color=0<br>
<br> 2018-10-27 17:37:10[pid: 32132]- Worker is started<br> 2018-10-27 17:37:11[1]Common\Jobs\CopyAssetJob (attempt: 1, PID: 32132) - Started<br> 2018-10-27 17:37:11[1]Common\Jobs\CopyAssetJob (attempt: 1, PID: 32132) - Error (0.232 S)<br> > Yii\Web\ServerErrorHttpException: based on task ID: 2, find the list of enabled resources is empty<br> 2018-10-27 17:37:11[pid: 32132]- Worker is stopped (0:00:01)</p> <p>jobs<br> - Waiting: 0<br> - delayed: 0<br> - reserved: 0<br> - done: 1</p> <p>jobs<br> - Waiting: 0<br> - delayed: 0<br> - reserved: 0<br> - done: 0</p> <p>jobs<br> - Waiting: 1<br> - delayed: 0<br> - reserved: 0<br> - done: 0<br>
13. View the exception information of the system log table, that is, the message in the log table, which is helpful for the analysis of subsequent developers, as shown in Figure 4

<br>
[1]Common\Jobs\CopyAssetJob (attempt: 1, PID: 32132) is finished with error: Yii\Web\ServerErrorHttpException: based on task ID: 2, find the list of enabled resources is empty in E:\wwwroot\channel-pub-api\common\jobs\copyassetjob.php:38<br>
stack trace:<br>
#0 e:\wwwroot\channel-pub-api\vendor\yiisoft\yii2-queue\src\queue.php(214): Common\Jobs\CopyAssetJob->Execute(Object(Yii\Queue\Redis\Queue))<br>
#1 e:\wwwroot\channel-pub-api\vendor\yiisoft\yii2-queue\src\cli\queue.php(162): yii\Queue\Queue->HandleMessage(1,o:24:"common\\jo...,600,1)<br>
#2 e:\wwwroot\channel-pub-api\vendor\yiisoft\yii2-queue\src\cli\command.php(145): Yii\Queue\Cli\Queue->Execute(1,o:24:"common\\jo...,600,1,32132)<br>
#3[internal function]: yii\queue\cli\command->ActionExec(1,600,1,32132)<br>
#4 e:\wwwroot\channel-pub-api\vendor\yiisoft\yii2\base\inlineaction.php(57): call_user_func_array(array, array)<br>
#5 e:\wwwroot\channel-pub-api\vendor\yiisoft\yii2\base\controller.php(157): Yii\Base\InlineAction->RunWithParams(Array)<br>
#6 e:\wwwroot\channel-pub-api\vendor\yiisoft\yii2\console\controller.php(148): Yii\Base\Controller->RunAction(Exec, array)<br>
#7 e:\wwwroot\channel-pub-api\vendor\yiisoft\yii2\base\module.php(528): yii\console\controller->runaction(Exec, array)<br>
#8 E:\wwwroot\channel-pub-api\vendor\yiisoft\yii2\console\application.php(180): yii\base\module->RunAction(copy-asset-queu..., array)<br>
#9 e:\wwwroot\channel-pub-api\vendor\yiisoft\yii2\console\application.php(147): yii\console\application->RunAction(copy-asset-queu..., array)<br>
#10 e:\wwwroot\channel-pub-api\vendor\yiisoft\yii2\base\application.php(386): Yii\Console\Application->HandleRequest(Object(Yii\Console\Request))<br>
#11 e:\wwwroot\channel-pub-api\yii(23): yii\base\application->run()<br>
#12 {main}.<br>
14. After the publishing task fails, insert the release log, push the job to the source callback queue (asynchronous), check the message in the release log table, that is, pub_log, this is business data, and it will be displayed to the user in the end, as shown in Figure 5

<br> Based on task ID: 2, find the list of enabled resources is empty<br>