您当前的位置: 首页 > 慢生活 > 程序人生 网站首页程序人生
新建Task相关的逻辑(laravel11队列的实现)
发布时间:2024-11-06 13:19:21编辑:雪饮阅读()
-
在开始使用 Laravel 队列之前,了解 “connections” 和 “queues” 之间的区别很重要。在您的配置文件中,有一个 configuration array。此选项定义与后端队列服务(如 Amazon SQS、Beanstalk 或 Redis)的连接。但是,任何给定的队列连接都可能具有多个“队列”,这些队列可以被视为不同的堆栈或排队作业堆。config/queue.phpconnections
请注意,配置文件中的每个连接配置示例都包含一个属性。这是作业在发送到给定连接时将被调度到的默认队列。换句话说,如果你分派一个作业而没有明确定义它应该被分派到哪个队列,则该作业将被放置在连接配置属性中定义的队列中:queuequeuequeue
use App\Jobs\ProcessPodcast;
//该任务将被派发到默认的连接中的queue队列
ProcessPodcast::dispatch();
// /该任务将被派发到默认的连接中的emails队列
ProcessPodcast::dispatch()->onQueue('emails');
某些应用程序可能不需要将作业推送到多个队列,而是更喜欢使用一个简单的队列。但是,将作业推送到多个队列对于希望确定作业处理方式的优先级或对其进行分段的应用程序特别有用,因为 Laravel 队列工作程序允许您指定它应按优先级处理哪些队列。例如,如果您将作业推送到队列,则可以运行一个为它们提供更高处理优先级的工作程序:high
php artisan queue:work --queue=high,default
为了使用队列驱动程序,您需要一个数据库表来保存作业。通常,这包含在 Laravel 的默认database0001_01_01_000002_create_jobs_table.php 数据库迁移;但是,如果您的应用程序不包含此迁移,则可以使用 Artisan 命令创建它:make:queue-table
php artisan make:queue-table
php artisan migrate
默认情况下,应用程序的所有可排队作业都存储在该目录中。如果该目录不存在,它将在运行Artisan命令时创建:
php artisan make:job ProcessPodcast
正好我这里就是没有jobs目录于app目录下
所以
./vendor/bin/sail artisan make:job ProcessProject
生成的类将实现接口,指示Laravel应该将作业推到队列中以异步运行。asynchronously.Illuminate\Contracts\Queue\ShouldQueue
作业存根可以使用存根发布来定制。
建立好项目队列处理进程后,我们就需要将之前的导出excel逻辑搬迁到这里的handle方法体中
public function handle(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$projects=Project::with(["user","categoryInfo"])->orderBy('id',"desc")->get();
$sheet->setCellValue('A1', 'ID');
$sheet->setCellValue('B1', '项目名称');
$sheet->setCellValue('C1', '项目封面');
$sheet->setCellValue('D1', '所属用户');
$sheet->setCellValue('E1', '所属分类');
$lastColumnWidth=null;
foreach ($projects as $key=>$val){
$currentRowNum=$key+2;
$sheet->setCellValue('A'.$currentRowNum, $val->id);
$sheet->setCellValue('B'.$currentRowNum, $val->name);
//echo $val->avatar."<br/>";
// 使用正则表达式匹配文件名
$avatarPath=null;
$tmpNames=[];
if($val->avatar_fs_path){
echo "正在绘制图像<br/>\r\n";
$drawing = new Drawing();
$drawing->setName('Sample Image');
$drawing->setDescription('Sample Image Description');
$drawing->setPath($val->avatar_fs_path); // 这里是你的图片路径
// 图片高度,单位为像素
//$drawing->setHeight(100);
// 图片宽度,单位为像素
// $drawing->setWidth(100);
$drawing->setCoordinates('C'.$currentRowNum); // 图片插入的单元格位置
$drawing->setWorksheet($sheet);
// 获取图片的尺寸
list($imageWidth, $imageHeight) = getimagesize($val->avatar_fs_path);
// 调整列宽以适应图片(这里假设图片在C列)
// 注意:Excel的列宽单位是以字符的1/256为单位的,这里我们将像素宽度转换为Excel的列宽单位
// 通常,一个字符的宽度大约是7像素(这取决于字体和字号),但这里我们为了简化,使用一个近似的转换比例
// 你可能需要根据实际情况调整这个比例
// 假设字符宽度为7像素,并除以10来得到一个较宽的列(这是一个近似值)
$excelColumnWidth = ($imageWidth / 1) * 256 / 10;
$excelColumnWidth=4*7;
if($lastColumnWidth==null || $excelColumnWidth>$lastColumnWidth){
$sheet->getColumnDimension('C')->setWidth($excelColumnWidth);
}
}
if($val->user){
$sheet->setCellValue('D'.$currentRowNum, $val->user->name);
}
if($val->categoryInfo){
$sheet->setCellValue('E'.$currentRowNum, $val->categoryInfo->name);
}
}
$sheet->setTitle('Demo Sheet');
$writer = new Xlsx($spreadsheet);
$filename = public_path()."/excel/".date("Y_m_d_H_i_s").'.xlsx';
$writer->save($filename);
echo "导出成功:".$filename;
}
由于命令行的特殊性所以换行就是\r\n,以及最后save的时候一定要使用绝对路径,因为和fastcgi时运行时不同,fastcgi运行时php出于web根目录,在laravel中即为public目录,而在命令行时(队列执行是在命令行下执行(同步情况还不是很清楚就是了))php的位置应该就是相对于bin\php哪里吧。
所以这里使用了public_patch方法,这是laravel11提供的。
那么接下来我们再于project控制器中定义一个方法派发导出excel任务到队列
public function exportAsync(){
ProcessProject::dispatch();
}
路由当然不要忘了
Route::get('/project/exportAsync', [ProjectController::class, 'exportAsync'])->name('project.exportAsync');
当然为了对比队列的异步处理,或者证实队列是异步处理的,所以我们需要将即将导出的数据记录变的非常多,这样进行导出对比的时候可以通过浏览器等待导出请求的响应时间进行对比。
public function exportAdd(){
$projects=Project::get();
foreach($projects as $v){
$project=new Project();
$project->name=$v->name;
$project->uid=$v->uid;
$project->avatar=$v->avatar;
$project->category=$v->category;
$project->avatar_fs_path=$v->avatar_fs_path;
$project->save();
}
}
该方法多执行几次,每次执行后看看原来的导出耗时,我是拼凑到1000多毫秒的。
同样路由别落下
Route::get('/project/exportAdd', [ProjectController::class, 'exportAdd'])->name('project.exportAdd');
任务派发后却并不一定执行,官方文档提到需要用
artisan queue:work
这个命令要一直在运行的状态下,会不断监听有新的任务派发后才根据策略运行任务的。
但该命令 有个缺点就是不响应文件变动,如果代码修改后则需要重新启动该命令。
所以推荐如
./vendor/bin/sail artisan queue:listen
但是该命令又是性能不怎么好,但是仅仅目前的话,我还是比较喜欢这个。
由于让任务进入队列进行执行的时候则一般都是希望是异步执行,则此情况下,如果有错误发生就不太容易排查,而默认的laravel11的错误日志不在文件里面(其他部署方式不清楚,反正我是通过官方提供的docker部署于Linux的),而是可以通过
./vendor/bin/sail artisan pail -v
来实时监听日志信息。
那么咱们再来看看这个性能的对比,从1000毫秒到90毫秒的性能优化
可以说是很给力了。
本期词汇
Creation 创造,创建
async 异步,非同步(asynchronous)
Podcast 播客 将……做成播客
关键字词:laravel,队列
相关文章
- SOC原则与repository设计模式(laravel11)
- 项目显示相关的逻辑、resource路由与resource control
- 权限与数据归属问题的几个方法(laravel11)
- laravel11编辑项目的数据验证逻辑、同一页面多表单错
- 编辑保存项目的逻辑(laravel里的两种数据绑定)
- 编辑项目的模态框样式(laravel11)
- unique rule的进一步限定与项目分类悬浮状态条效果实
- 新建项目的数据验证(基于laravel11+inertia的数据验证
- 新建项目表单的模态框样式(laravel11+inertia+breeze
- laravel中的一对多关系使用与inertia的link使用