一、前言
- 最近赶在5月1的上线大关,一直没有来得及更新。
- 前段时间,有读者建议我出一个 Lumen 项目示例,目前只实现了部分功能,后面有时间慢慢补全逻辑和完善注释。
- 同样也要借此机会,介绍一下 Module(模块化) 的项目结构,针对本文,具体的目录层次如下:
/app
....../Base # 定义基础类
....../Common # 定义常量、全局函数
....../Middlewares
....../Modules
....../....../Job # Job模块
....../....../Task # Task模块
....../Providers
............others............
/bootstrap
/config # 配置文件目录
/database
/routes
......others.......
二、说明
- 还没有书写注释和完整的业务逻辑,所以新手可能理解难度较高。
- 本文的项目背景是 ,基于 Lumen 开箱即用的 队列 实现。
- 项目开发环境使用最新的 Lumen 5.8.x 以及 PHP 7.2.16 版本。
- 快速上手,可以使用本人至今 'Windows' 下正常开发使用的。
三、开始
-
确定本地已经安装了 Composer 环境。
-
注意,git clone 完成后要执行
composer install
安装依赖。 -
目前已经实现的功能如下:
添加定时任务 | 查询定时任务 | 定时任务列表 |
---|---|---|
{{base_url}}/api/task/add |
{{base_url}}/api/task/seek/{task_uuid} |
{{base_url}}/api/task/all |
5.1. 添加定时任务接口
HTTP/1.1 200 OK. POST {{base_url}}/api/task/add
@请求模板:
{
"callback_url": "http://127.0.0.1:8001",
"callback_header": {
"Content-Type": "application/json"
},
"callback_time": "2019-4-22 16:21:51",
"task_title": "test task",
"callback_body": {
"course_id": 1,
"lesson_id": 25
}
}
@成功响应:
{
"status_code": 200,
"data": {
"task_uuid": "54ddf0cceecac4b3349c3f3bffab1f8e",
"status": "待执行",
"task_title": "test task",
"created_at": "2019-04-30 11:18:20",
"first_execute": "",
"success_execute": "",
"failure_execute": ""
}
}
5.2. 查询定时任务接口
HTTP/1.1 200 OK. POST {{base_url}}/api/task/seed/{task_uuid}
task_uuid = 54ddf0cceecac4b3349c3f3bffab1f8e
@成功响应:
{
"status_code": 200,
"data": {
"task_uuid": "54ddf0cceecac4b3349c3f3bffab1f8e",
"status": "待执行",
"task_title": "test task",
"created_at": "2019-04-30 11:18:20",
"first_execute": "",
"success_execute": "",
"failure_execute": ""
}
}
5.1. 定时任务列表接口
HTTP/1.1 200 OK. POST {{base_url}}/api/task/all
@成功响应:
{
"status_code": 200,
"data": {
"pagination": {
"total": 1,
"count": 1,
"per_page": 10,
"current_page": 1,
"last_page": 1
},
"data": [
{
"task_uuid": "de70b9b9bf5fb13ff6e96776839ceb15",
"status": "待执行",
"task_title": "test task",
"created_at": "2019-04-30 10:54:27",
"first_execute": "",
"success_execute": "",
"failure_execute": ""
}
]
}
}
- 贴出核心 'TaskJob.php' 下的代码,前往 ,可以查看完整代码文件。
<?php
namespace App\Modules\Task;
use App\Jobs\BaseJob;
use App\Modules\Job\JobModel;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;
class TaskJob extends BaseJob
{
const MAX_ATTEMPTS = 5;
/**
* @var array
*/
private $taskData;
/**
* @var TaskModel
*/
private $taskInstance;
/**
* @var JobModel
*/
private $jobInstance;
/**
* @var mixed
*/
private $response;
public function __construct(array $taskData)
{
$this->taskData = $taskData;
$this->setTaskInstance();
$this->setJobInstance();
}
public function handle()
{
$this->posting() ? $this->successEnding() : $this->errorEnding();
$this->delete();
return false;
}
private function setTaskInstance()
{
$taskContent = json_encode(Arr::except($this->taskData, ['task_title']));
$filled = ['task_uuid' => md5($taskContent . time()), 'task_content' => $taskContent, 'task_title' => $this->taskData['task_title']];
$this->taskInstance = (new TaskModel)->createOne($filled);
}
private function setJobInstance()
{
$this->jobInstance = (new JobModel)->createOne();
}
public function getJobInstance()
{
return $this->jobInstance;
}
public function getTaskInstance()
{
return $this->taskInstance;
}
private function makeHeaders()
{
$temp = Arr::pull($this->taskData, 'callback_header');
$return = [];
foreach ($temp as $key => $value) {
$return[] = $key . ':' . $value;
}
return $return;
}
private function posting()
{
$url = Arr::pull($this->taskData, 'callback_url');
$body = Arr::pull($this->taskData, 'callback_body');
$headers = $this->makeHeaders();
$this->getTaskInstance()->activeOne();
$this->getJobInstance()->attempts($this->attempts());
// begin:
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
$this->response = curl_exec($curl);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
// end:
return ($httpCode == 200);
}
/**
* @author AdamTyn
* @description 处理成功结果
*
* @return void
*/
private function successEnding()
{
Log::alert(PHP_EOL . PHP_EOL . PHP_EOL . '<Success in 定时系统回调> at ' . date('Y-m-d H:i:s') . PHP_EOL . '<具体响应内容:> ' . 'detail=> ' . PHP_EOL . $this->response . PHP_EOL . PHP_EOL . PHP_EOL);
$this->getTaskInstance()->successOne($this->response);
}
/**
* @author AdamTyn
* @description 处理失败结果
*
* @return void
*/
private function errorEnding()
{
$log = PHP_EOL . PHP_EOL . PHP_EOL . '<Error in 定时系统回调> at ' . date('Y-m-d H:i:s') . PHP_EOL . '<具体错误内容:> ' . 'detail=> ' . PHP_EOL . $this->response . PHP_EOL . PHP_EOL . PHP_EOL;
Log::error($log);
if ($this->attempts() == self::MAX_ATTEMPTS) {
$this->getTaskInstance()->failureOne($this->response);
} else {
$this->release(mt_rand(5, 20));// 失败的定时任务,会推迟随机秒数后再执行
}
}
}
四、结语
- 本教程面向新手,更多教程会在日后给出。
- 随着系统升级,软件更新,以后的配置可能有所变化,在下会第一时间测试并且更新教程;
- 欢迎联系在下,讨论建议都可以,之后会发布其它的教程。
- 后面紧锣密鼓地将会推出 系列的教程,敬请期待。