主题
异步任务
概述
在 Web 应用开发中,有些操作可能需要较长的处理时间,如果在 HTTP 请求中直接处理这些操作,会导致用户等待时间过长,影响用户体验。异步任务就是为了解决这类问题而设计的,它允许将耗时操作放到后台执行,用户无需等待即可得到响应。
什么是异步任务?
异步任务是指将耗时的操作从主请求流程中分离出来,放到后台独立执行的一种机制。这样可以:
- 提高系统响应速度,避免用户长时间等待
- 合理分配系统资源,避免资源占用过高
- 提供任务执行状态的可视化监控
适用场景
异步任务适用于以下场景:
- 数据导入导出:处理大量数据的导入导出操作
- 发送邮件通知:批量发送邮件或消息通知
- 数据统计分析:需要长时间运行的数据统计和分析
- 文件处理:大文件的上传、处理、转换等操作
- 第三方 API 调用:调用响应较慢的外部服务
CatchAdmin 后台提供了一个完整的异步任务解决方案,包括可视化界面和易于接入的 API,使开发者能够轻松实现自己的后台异步任务。如下所示:
目前后台导入导出功能已经实现了异步任务处理,那么该如何自定义实现自己的异步任务呢?本文将详细介绍。
WARNING
异步任务执行默认是关闭的。请先到根目录下的 routes/console.php
按照提示打开即可
INFO
异步任务表结构
php
Schema::create('async_task', function (Blueprint $table) {
$table->id();
$table->string('task')->comment('task任务对应的 class 名称');
$table->string('params')->default('')->comment('任务所需参数');
$table->integer('start_at')->default(0)->comment('开始时间');
$table->tinyInteger('status')->default(1)->comment('状态:un_start=1,running=2,finished=3,error=4');
$table->integer('time_taken')->default(0)->comment('运行耗时');
$table->string('error')->default('')->comment('执行结果错误');
$table->string('result')->default('')->comment('执行结果');
$table->string('retry')->default(0)->comment('重试次数');
$table->createdAt();
$table->updatedAt();
$table->deletedAt();
});
定义
需要实现自定义的后台异步任务,需要实现一个异步任务接口 AsyncTaskInterface
php
namespace Catch\Contracts;
interface AsyncTaskInterface
{
/**
* push task
*/
public function push(): mixed;
/**
* run task
*/
public function run(array $params): mixed;
}
接口实现
php
use Modules\System\Models\AsyncTask;
class AsyncTask implements AsyncTaskInterface
{
// push 方法将当前任务推送到任务队列
public function push(): mixed
{
return app(AsyncTask::class)
->storeBy([
'task' => get_called_class(),
'params' => '', // 参数需要自定义实现
]);
}
// run 方法 任务具体业务线,它接受传进来的参数
public function run(array $params): mixed
{
// params 就是 push 进去的 params 参数
// 自定义实现任务
}
}
使用
在需要使用 AsyncTask
的地方,将任务推送到任务列表中
php
$async = new AsyncTask()
$async->push()
添加定时任务
到 系统管理
->定时任务
页面,添加如下图的定时任务配置
启动
WARNING
下面的命令是本地测试使用,切勿在线上使用
shell
php artisan schedule:work
示例
在用户模块modules/User
目录下,提供了一个完整的示例,基于用户导出。
WARNING
导出是经过包装的,不要直接使用,你需要自己实现异步接口的 push 和 run 方法来接入实际业务
php
namespace Modules\User\Export;
use Catch\Contracts\AsyncTaskInterface;
use Catch\Support\Excel\Export;
use Modules\System\Support\Traits\AsyncTaskDispatch;
class User extends Export implements AsyncTaskInterface
{
// 推送任务 trait
use AsyncTaskDispatch;
protected array $header = [
'id', '昵称', '邮箱', '创建时间',
];
// 查询出来导出的数据
public function array(): array
{
// TODO: Implement array() method.
return \Modules\User\Models\User::query()
->select('id', 'username', 'email', 'created_at')
->without('roles')
->get([
'id', 'username', 'email', 'created_at',
])->toArray();
}
}
php
// 推送 trait
namespace Modules\System\Support\Traits;
use Modules\System\Models\AsyncTask;
/**
* @method array getParams()
*/
trait AsyncTaskDispatch
{
public function push(): mixed
{
// 直接推送异步任务表
return app(AsyncTask::class)
->storeBy([
'task' => get_called_class(),
'params' => count($this->getParams()) ? json_encode($this->getParams()) : '',
]);
}
}
使用
php
public function export(\Modules\User\Export\User $export): mixed
{
return $export->push();
}
到 用户管理
页面点击导出之后,会生成这样一条任务。如下图
执行成功之后会生成如下图的 excel 文件