页面交互效果
下面是写好的示例前端交互页面,主要是列表页面,编辑页面。
主要交互有:
1 开启定时任务进程
2 关闭定时任务进程
3 新增一项定时任务
4 编辑已有的定时任务
5 删除定时任务
6 开始一项定时任务
7 停止一项定时任务
定时任务分两种:
1 执行一次
2 循环执行
定时任务执行的内容:
定时任务执行的内容其实还是一个http请求。 通过定时的方式,指定时间执行或者循执行。
1 列表页面
2 新建\编辑页面
代码地址,演示地址
示例代码是基于Laravel,Alpaca-spa框架编写,并且作为 ‘Alpaca-Spa-Laravel后台管理平台’的一个模块儿集成于系统中。
代码 : http://git.oschina.net/cc-sponge/Alpaca-Spa-Laravel
代码 : https://github.com/big-sponge/Alpaca-Spa-Laravel
Alpaca-Spa-Laravel : http://full.tkc8.com
Alpaca-Spa : http://www.tkc8.com
适用范围
定时精确时间不低于1秒。web服务重启、或者php重启。该定时任务不会自动重启。
实现原理
用PHP实现定时任务(非linux-shell方式,与操作系统平台无关),主要两个技术点:
1)PHP后台进程
2)PHP异步处理
1 PHP后台进程
一般情况,用命令行可以开启一个php后台进程。而在浏览器中通过HTTP请求一个php处理,会因为浏览器关闭,或者请求超时,使得后台的php处理中断。但是php提供了两个方法可以会忽略浏览器关闭、请求超时:
ignore_user_abort(true); // 忽略客户端断开
set_time_limit(0); // 设置执行不超时
因此,我们可以使用这两个函数从浏览器以HTTP请求的方式开启一个php后台进程。
2 PHP异步处理
php语言本身没有可以跨平台好用异步处理方法,但是可以通过curl或者fsockopen创建一个请求来实现异步处理。这里我们用fsockopen方法实现:
$fp = fsockopen("$ip", $port, $errno, $errstr,1);
if (!$fp) {
return 'worker error:'."$errstr ($errno)<br />\n";
} else {
$out = "POST $url HTTP/1.1\r\n";
$out .= "Host: $ip\r\n";
$out .= "Content-Type:application/x-www-form-urlencoded; charset=UTF-8\r\n";
$out .= "Content-Length: " . strlen($postData) . "\r\n";
$out .= "Connection: close\r\n";
$out .="\r\n";
$out .=$postData;
fputs($fp, $out);
fclose($fp);
}
前台交互控制器
为了在前端界面方便控制定时任务的开启关闭,新增、编辑、删除,查看执行状态。 同时也可以添加权限控制。 主要有8个操作接口(下面是以Laravel 路由示例):
1 查看定时任务进程状态
2 开始定时任务进程
3 停止定时任务进程
4 添加,或者编辑定时任务
5 设置定时任务状态
6 获取指定定时任务明细
7 删除定时任务
8 获取定时任务列表
/* crontab - status 查看定时任务守护进程状态 */
Route::any('crontab/status', "CrontabController@status");
/* crontab - start 开始定时任务 */
Route::any('crontab/start', "CrontabController@start");
/* crontab - stop 停止定时任务守护进程*/
Route::any('crontab/stop', "CrontabController@stop");
/* crontab - editTask 添加,或者编辑定时任务*/
Route::any('crontab/editTask', "CrontabController@editTask");
/* crontab - changeTaskStatus 设置定时任务状态 */
Route::any('crontab/changeTaskStatus', "CrontabController@changeTaskStatus");
/* crontab - getIndexTask 获取指定定时任务 */
Route::any('crontab/getIndexTask', "CrontabController@getIndexTask");
/* crontab - removeTask 删除定时任务 */
Route::any('crontab/removeTask', "CrontabController@removeTask");
/* crontab - listTask 获取定时任务列表 */
Route::any('crontab/listTask', "CrontabController@listTask");
完整的类代码如下:
<?php
namespace App\Modules\Manage\Controllers;
use Crontab\Library\Crontab\AlpacaCrontab;
use Crontab\Library\Crontab\AlpacaDaemon;
use Crontab\Library\Crontab\AlpacaWorker;
use App\Modules\Manage\Controllers\Base\BaseController;
use App\Common\Code;
use App\Common\Msg;
/**
* 定时任务管理控制器
* @author Chengcheng
* @date 2016-10-19 15:50:00
*/
class CrontabController extends BaseController
{
/**
* 设置不需要登录的的Action,不加Action前缀
* @author Chengcheng
* @date 2016年10月23日 20:39:25
* @return array
*/
protected function noLogin()
{
return [];
}
/**
* 设置不需要权限验证的Action,不加Action前缀
* @author Chengcheng
* @date 2016年10月23日 20:39:25
* @return array
*/
protected function noAuth()
{
// 以下Action不需要角色权限
return [];
}
/**
* 查看定时任务守护进程状态
* @author Chengcheng
* @date 2016-10-23 20:34:00
*/
public function status()
{
//查看守护进程状态
$result['code'] = Code::SYSTEM_OK;
$result['msg'] = Msg::SYSTEM_OK;
$result['data'] = AlpacaDaemon::daemon()->status();
//返回结果
return $this->ajaxReturn($result);
}
/**
* 开始定时任务
* @author Chengcheng
* @date 2016-10-23 20:34:00
*/
public function start()
{
//异步开启守护进程
$result['code'] = Code::SYSTEM_OK;
$result['msg'] = Msg::SYSTEM_OK;
$result['data'] = AlpacaWorker::worker()->action(['REQUEST_URI' => "/crontab/index/start"]);
//返回结果
return $this->ajaxReturn($result);
}
/**
* 停止定时任务守护进程
* @author Chengcheng
* @date 2016-10-23 20:34:00
*/
public function stop()
{
//停止守护进程
$result['code'] = Code::SYSTEM_OK;
$result['msg'] = Msg::SYSTEM_OK;
$result['data'] = AlpacaDaemon::daemon()->stop();
//返回结果
return $this->ajaxReturn($result);
}
/**
* 添加,或者编辑定时任务
* @author Chengcheng
* @date 2016-10-23 20:34:00
*/
public function editTask()
{
/*
* 1 获取输入参数
* BEGIN_TIME 开始时间
* END_TIME 结束时间
* INTERVAL 时间间隔
* NAME 名称
* STATUS 状态 1-ENABLED, 2-DISABLE
* TASK_TYPE 类型 1-ONCE, 2-LOOP
* ACTION 要执行的Action
* INDEX 索引,null或者0时候,表示新建
* */
$this->requestData['NAME'] = $this->input('NAME', null);
$this->requestData['BEGIN_TIME'] = $this->input('BEGIN_TIME', null);
$this->requestData['END_TIME'] = $this->input('END_TIME', null);
$this->requestData['INTERVAL'] = $this->input('INTERVAL', null);
$this->requestData['TASK_TYPE'] = $this->input('TASK_TYPE', '1');
$this->requestData['ACTION'] = $this->input('ACTION', null);
$this->requestData['STATUS'] = $this->input('STATUS', '2');
$this->requestData['INDEX'] = $this->input('INDEX', null);
$this->requestData['LAST_TIME'] = $this->input('LAST_TIME', null);
//2 检查参数
if (empty($this->requestData['BEGIN_TIME'])) {
$result["code"] = Code::SYSTEM_PARAMETER_NULL;
$result["msg"] = sprintf(Msg::SYSTEM_PARAMETER_N