写个定时任务,没有权限。其实蛮好的,只要写业务逻辑然后交给 别人 挂服务器上就O了。
有些蛋疼的是,要是搬服务器呢?所以心血来潮,虫子上脑,耗点服务器资源了,不存在硬件上的问题。
有时候弄点东西,先不要考虑哪些杂七杂八的东西,可以节省很多时间。
原理如下:
1.curl调起1毫秒后 挂起运行
2.调起 “”条件“” 死循环,满足 条件从条件中删除不进行下一次循环,不满足进入下一次循环
3.死循环 休息机制,防止一直跑,把服务器给弄没了
4.死循环跳出
5.再次调起运行条件
代码如下:
<?php
namespace app\shop\controller\sys_admin;
use app\AdminController;
use think\facade\Cache;
use think\Db;
/* ------------------------------------------------------ */
//订单相关
/* ------------------------------------------------------ */
/**
* @author lianyu
*/
class Lianyu extends AdminController {
private $redis_status = [
"create", //创建时,超时处理
"shipping", //发货时,自动收货处理
"sign" //签收时,无售后处理 返佣
];
private $shop_order_auto_cancel = 1; //超时取消
private $shop_auto_sign_limit = 1; //自动签收
private $shop_after_sale_limit = 1; //关闭售后
private $config;
private $run_day = 30; //运行天数
/* ------------------------------------------------------ */
//-- 优先执行
/* ------------------------------------------------------ */
public function initialize() {
parent::initialize();
$this->Model = new \app\mainadmin\model\SettingsModel();
$this->set_val();
// $this->kill_var($setmod);
}
/* ------------------------------------------------------ */
//-- 首页
/* ------------------------------------------------------ */
/**
* 处理各定时状态
*/
public function index() {
$p4 = $this->calculate(); //手动添加
//异步调起程序
$request_url = $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; //当前URL
$where = end(explode('/', $request_url));
$path = str_replace($where, '', $request_url);
$auto_cancel = $path . "auto_cancel";
// $this->p($auto_cancel, 1, 0);
// $this->doRequest($auto_cancel); //订单支付超时链接
$p1 = $this->curl_request($auto_cancel);
$auto_sign = $path . "auto_sign/type/4";
// $this->p($auto_sign, 1, 0);
// $this->doRequest($auto_sign); //订单签收超时链接
$p2 = $this->curl_request($auto_sign);
$after_sale = $path . "after_sale/type/4";
// $this->p($after_sale, 1, 0);
// $this->doRequest($after_sale); //订单超时链接
$p3 = $this->curl_request($after_sale);
echo "end";
}
/**
* 计算是否断开过,搜索数据库,然后存入redis
*/
function calculate() {
$time = time();
//redis操作
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379); //开放端口
$redis->auth(); //密码
$redis->select(0); //选择数据库
$order_mod = new \app\shop\model\OrderModel();
$size = (int) @readfile('./error/auto_cancel.txt'); //程序最后更新时间
if ($size + 10 < $time) {
//获取下单未支付未取消订单 ID
$where = "confirm_time > 0 and pay_time = 0 and cancel_time = 0 ";
$ary = $order_mod->field("order_id")->where($where)->select()->toArray();
foreach ($ary as $val) {
$redis->lPush($this->redis_status[0], $val['order_id']); //加入队列 返回队列总数
}
}
$size = (int) @readfile('./error/auto_sign.txt');
if ($size + 10 < $time) {
//获取发货未签收订单 ID
$where = "shipping_time > 0 and sign_time = 0 and cancel_time = 0 ";
$ary = $order_mod->field("order_id")->where($where)->select()->toArray();
foreach ($ary as $val) {
$redis->lPush($this->redis_status[1], $val['order_id']); //加入队列 返回队列总数
}
}
$size = (int) @readfile('./error/after_sale.txt');
if ($size + 10 < $time) {
//获取签收订单售后期内订单 ID
$where = "sign_time > 0 and after_sale_qualification = 1";
$ary = $order_mod->field("order_id")->where($where)->select()->toArray();
foreach ($ary as $val) {
$redis->lPush($this->redis_status[2], $val['order_id']); //加入队列 返回队列总数
}
}
}
/**
* 设置参数
*/
function set_val() {
$this->config = config('config.');
$this->shop_order_auto_cancel = $this->Model->where("name", "shop_order_auto_cancel")->value("data");
$this->shop_auto_sign_limit = $this->Model->where("name", "shop_auto_sign_limit")->value("data");
$this->shop_after_sale_limit = $this->Model->where("name", "shop_after_sale_limit")->value("data");
$this->shop_order_auto_cancel*=60; //得出超时 秒
$this->shop_auto_sign_limit*=86400; //得出自动签收 秒
$this->shop_after_sale_limit*=86400; //得出无法售后时间 秒
//测试使用
// $this->shop_order_auto_cancel = 5;
// $this->shop_auto_sign_limit = 5;
// $this->shop_after_sale_limit = 5;
}
/**
* 订单下单超时处理,未支付状态超时处理
*/
function auto_cancel() {
ignore_user_abort(true); // 忽略客户端断开
set_time_limit(0); // 设置执行不超时
$time = time();
$action = $this->request->action();
/**
* 读取文件秒数
* 如果与当前时间不超过10秒
* 则说明程序正在运行,不再再次运行。
* 可以多次调用该程序,从而加快从redis拿出的频率,提高处理速度,相对 多消耗一倍服务器资源
* 这里只做一次,唯一调用
*/
$size = (int) @readfile('./error/' . $action . '.txt');
if ($size + 10 > $time) {
return true;
} else {
//初始化参数
data_log_w("1", $action . "_day.txt"); //日期参数
$i = 1; //循环次数
$maxi = 10000; //多少次循环休息
$sleep = 1; //休息时间
$_log = '超时自动取消'; //日志sql写入
}
$order_mod = new \app\shop\model\OrderModel();
//redis操作
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379); //开放端口
$redis->auth(); //密码
$redis->select(0); //选择数据库
while (TRUE) {
$now_time = time();
data_log_w($now_time, $action . ".txt"); //更新判断次程序运行文件
$order_id = $redis->lPop($this->redis_status[0]); //出队 $this->Model->redis_sel($this->redis_status[0]);
// output($order_id);
if (empty($order_id)) {
sleep($sleep); //休息
continue;
}
//每10000次休息1秒中,每秒处理1w条
if ($i > $maxi) {
$i = 1;
sleep($sleep);
}
$i++;
// 如果订单不存在超时情况,释放队列进入下一次循环
if ($this->shop_order_auto_cancel == 0) {
continue;
}
$day = (int) @readfile('./error/' . $action . '_day.txt');
//运行超过30天则停掉该程序,重新调用
if ($day > $this->run_day) {
data_log("redis 超时订单处理等待再次调用,运行时间" . date("Y-m-d H:i:s", $time) . " 到 " . date("Y-m-d H:i:s", $now_time), "run.txt");
break;
}
/* 每隔1天刷新后台设置 */
if (($now_time - $time) > ($day * 86400)) {
++$day;
data_log_w($day, $action . "_day.txt");
$this->set_val(); //
}
//获取订单信息
$where['order_id'] = $order_id;
$order = $order_mod->where($where)->find(); //确认时间
//已支付,释放队列
if ($order['pay_time'] > 0 || empty($order)) {
continue;
} elseif (($order['add_time'] + $this->shop_order_auto_cancel) < $now_time) {
//订单超时处理
$mkey = 'OrderIng_' . $order_id;
Cache::set($mkey, 1);
$upData['order_id'] = $order_id;
$upData['order_status'] = $this->config['OS_CANCELED'];
$upData['cancel_time'] = $now_time;
$upData['update_time'] = $now_time; //最后更新时间
$res = $order_mod->upInfo($upData);
// output($res);
Cache::rm($mkey);
if ($res === true) {
$orderInfo = $order_mod->info($order_id);
$order_mod->_log($orderInfo, $_log);
}
} else {
//订单没有超时,也没有其他操作,重新放回队列
$redis->lPush($this->redis_status[0], $order_id); //加入队列 返回队列总数
}
//内存清理
$this->kill_var($now_time);
$this->kill_var($order_id);
$this->kill_var($day);
$this->kill_var($where);
$this->kill_var($order);
$this->kill_var($mkey);
$this->kill_var($upData);
$this->kill_var($res);
$this->kill_var($orderInfo);
}
exit();
}
/**
* 订单自动签收
*/
function auto_sign() {
ignore_user_abort(true); // 忽略客户端断开
set_time_limit(0); // 设置执行不超时
$time = time();
$action = $this->request->action();
/**
* 读取文件秒数
* 如果与当前时间不超过10秒
* 则说明程序正在运行,不再再次运行。
* 可以多次调用该程序,从而加快从redis拿出的频率,提高处理速度,相对 多消耗一倍服务器资源
* 这里只做一次,唯一调用
*/
$size = (int) @readfile('./error/' . $action . '.txt');
if ($size + 10 > $time) {
return true;
} else {
//初始化参数
data_log_w("1", $action . "_day.txt"); //日期参数
$i = 1; //循环次数
$maxi = 10000; //多少次循环休息
$sleep = 1; //休息时间
$_log = '超时自动签收'; //日志sql写入
}
$order_mod = new \app\shop\model\OrderModel();
$mod = new \app\member\controller\api\Zx();
//redis操作
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379); //开放端口
$redis->auth(); //密码
$redis->select(0); //选择数据库
while (TRUE) {
$now_time = time();
data_log_w($now_time, $action . ".txt"); //更新判断次程序运行文件
$order_id = $redis->lPop($this->redis_status[1]); //出队
// output($order_id);
if (empty($order_id)) {
sleep($sleep); //休息
continue;
}
//每10000次休息1秒中,每秒处理1w条
if ($i > $maxi) {
$i = 1;
sleep($sleep);
}
$i++;
// 如果订单不存在收货超时情况,释放队列进入下一次循环
if ($this->shop_auto_sign_limit == 0) {
continue;
}
$day = (int) @readfile('./error/' . $action . '_day.txt');
//运行超过30天则停掉该程序,重新调用
if ($day > $this->run_day) {
data_log("redis 超时自动签收订单等待再次调用,运行时间" . date("Y-m-d H:i:s", $time) . " 到 " . date("Y-m-d H:i:s", $now_time), "run.txt");
break;
}
/* 每隔1天刷新后台设置 */
if (($now_time - $time) > ($day * 86400)) {
++$day;
data_log_w($day, $action . "_day.txt");
$this->set_val(); //
}
//获取订单信息
$where['order_id'] = $order_id;
$order = $order_mod->where($where)->find(); //订单信息
//已收货,释放队列
if ($order['sign_time'] > 0 || empty($order)) {
continue;
} elseif (($order['shipping_time'] + $this->shop_auto_sign_limit) < $now_time) {
//订单签收超时处理
$mkey = 'OrderIng_' . $order_id;
Cache::set($mkey, 1);
$upData['order_id'] = $order_id;
$upData['shipping_status'] = $this->config['SS_SIGN'];
$upData['sign_time'] = $now_time;
$upData['update_time'] = $now_time; //最后更新时间
$res = $order_mod->upInfo($upData);
Cache::rm($mkey);
if ($res === true) {
$orderInfo = $order_mod->info($order_id);
$order_mod->_log($orderInfo, $_log);
$mod->pid_bonuses($order_id); //返佣处理
// $redis->lPush($this->redis_status[2], $order_id);//加入售后队列
}
} else {
//订单没有超时,也没有其他操作,重新放回队列
$redis->lPush($this->redis_status[1], $order_id); //加入队列 返回队列总数
}
//内存清理
$this->kill_var($now_time);
$this->kill_var($order_id);
$this->kill_var($day);
$this->kill_var($where);
$this->kill_var($order);
$this->kill_var($mkey);
$this->kill_var($upData);
$this->kill_var($res);
$this->kill_var($orderInfo);
}
exit();
}
/**
* 订单自动无售后
*/
function after_sale() {
ignore_user_abort(true); // 忽略客户端断开
set_time_limit(0); // 设置执行不超时
$time = time();
$action = $this->request->action();
/**
* 读取文件秒数
* 如果与当前时间不超过10秒
* 则说明程序正在运行,不再再次运行。
* 可以多次调用该程序,从而加快从redis拿出的频率,提高处理速度,相对 多消耗一倍服务器资源
* 这里只做一次,唯一调用
*/
$size = (int) @readfile('./error/' . $action . '.txt');
if ($size + 10 > $time) {
return true;
} else {
//初始化参数
data_log_w("1", $action . "_day.txt"); //日期参数
$i = 1; //循环次数
$maxi = 10000; //多少次循环休息
$sleep = 1; //休息时间
$_log = '售后过期'; //日志sql写入
}
$order_mod = new \app\shop\model\OrderModel();
$mod = new \app\member\controller\api\Zx();
//redis操作
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379); //开放端口
$redis->auth(); //密码
$redis->select(0); //选择数据库
while (TRUE) {
$now_time = time();
data_log_w($now_time, $action . ".txt"); //更新判断次程序运行文件
$order_id = $redis->lPop($this->redis_status[2]); //出队
// output($order_id);
if (empty($order_id)) {
sleep($sleep); //休息
continue;
}
//每10000次休息1秒中,每秒处理1w条
if ($i > $maxi) {
$i = 1;
sleep($sleep);
}
$i++;
// 如果订单不存在收货超时情况,释放队列进入下一次循环
if ($this->shop_after_sale_limit == 0) {
continue;
}
$day = (int) @readfile('./error/' . $action . '_day.txt');
//运行超过30天则停掉该程序,重新调用
if ($day > $this->run_day) {
data_log("redis 售后超时订单等待再次调用,运行时间" . date("Y-m-d H:i:s", $time) . " 到 " . date("Y-m-d H:i:s", $now_time), "run.txt");
break;
}
/* 每隔1天刷新后台设置 */
if (($now_time - $time) > ($day * 86400)) {
++$day;
data_log_w($day, $action . "_day.txt");
$this->set_val(); //
}
//获取订单信息
$where['order_id'] = $order_id;
$order = $order_mod->where($where)->find(); //订单信息
//已售后,释放队列
if ($order['after_sale_qualification'] == 0 || empty($order) || $order['is_after_sale'] != 0) {
continue;
} elseif (($order['sign_time'] + $this->shop_after_sale_limit) < $now_time) {
//订单签收超时处理
$upData['order_id'] = $order_id;
$upData['after_sale_qualification'] = 0;
$upData['update_time'] = $now_time; //最后更新时间
$res = $order_mod->upInfo($upData);
if ($res === true) {
$orderInfo = $order_mod->info($order_id);
$order_mod->_log($orderInfo, $_log);
$mod->pid_bonuses($order_id, 1); //返佣处理
}
} else {
//订单没有超时,也没有其他操作,重新放回队列
$redis->lPush($this->redis_status[2], $order_id); //加入队列 返回队列总数
}
//内存清理
$this->kill_var($now_time);
$this->kill_var($order_id);
$this->kill_var($day);
$this->kill_var($where);
$this->kill_var($order);
$this->kill_var($upData);
$this->kill_var($res);
$this->kill_var($orderInfo);
}
exit();
}
/**
* 异步访问
* @param type $url 需要访问的url
* @param type $param 携带参数
*/
function doRequest($url, $param = array()) {
$urlinfo = parse_url($url);
$host = $urlinfo['host'];
$path = $urlinfo['path'];
$query = isset($param) ? http_build_query($param) : '';
$port = 80;
$errno = 0;
$errstr = '';
$timeout = 10;
$fp = fsockopen($host, $port, $errno, $errstr, $timeout);
$out = "POST " . $path . " HTTP/1.1\r\n";
$out .= "host:" . $host . "\r\n";
$out .= "content-length:" . strlen($query) . "\r\n";
$out .= "content-type:application/x-www-form-urlencoded\r\n";
$out .= "connection:close\r\n\r\n";
$out .= $query;
fputs($fp, $out);
fclose($fp);
}
//参数1:访问的URL,参数2:响应超时时间 毫秒
function curl_request($url = "http://www.baidu.com", $ms = 100) {
//初始化
$curl = curl_init();
//设置抓取的url
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_NOSIGNAL, 1); //注意,毫秒超时一定要设置这个
curl_setopt($curl, CURLOPT_TIMEOUT_MS, $ms); //超时毫秒,cURL 7.16.2中被加入。从PHP 5.2.3起可使用
// curl_setopt($curl, CURLOPT_TIMEOUT, $s);//超时时间 秒
// curl_setopt($curl, CURLOPT_HEADER, 1);//设置头文件的信息作为数据流输出
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); //设置获取的信息以文件流的形式返回,而不是直接输出。
//执行命令
$data = curl_exec($curl);
//关闭URL请求
curl_close($curl);
//显示获得的数据
return $data;
}
/**
* 每日零点,自动将账户内当前的快乐豆按当前后台设定的比例自动转化为余额;
* 激活条件: 时间处于每日 00:00:00 到 00:00:59之间
* 运算逻辑:
* users_account 表 快乐豆字段清零
* 设置临时表数据(数据复制一份到新表)无数据锁定
* 临时表数据运算 更新存储表(已有快乐豆-新表快乐豆 = 现有快乐豆 无今天更新情况下 为0 )
* 添加日志
* 临时表数据清0 truncate
* 数据可能超百万,采用多线程分批处理,每批处理1w,采用异步处理
*
* 获取比例,得出余额
* 用户余额添加 比例余额
* 添加快乐豆日志表
* 添加余额日志表
*/
function ff() {
ignore_user_abort(true); // 忽略客户端断开
set_time_limit(0); // 设置执行不超时
$now_time = time();
if (date("H:i", $now_time) != "00:00") {
$this->error("运行时间错误");
}
$bl = $this->Model->where("name", "intergral")->value("data"); //获取比例
if (empty($bl)) {
$this->error("比例未设置");
}
$p = input("p", 1);
$row = 10000; //每次处理一万条数据
$limit = ($p - 1) * $row . "," . $row;
if ($p == 1) {
Db::query("drop table users_account_copy;"); //删除表
$res = Db::query("create table users_account_copy (select user_id,((use_integral*100 div " . $bl . ")/100) as balance_money2,"
. "use_integral,balance_money from users_account where use_integral >0);"); //表生成
if ($res === false) {
$this->error("Create Table Error.");
}
}
$count = Db::table("users_account_copy")->count();
if ($count > (($p - 1) * $row)) {
++$p;
//异步处理
$request_url = $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; //当前URL
$where = end(explode('/', $request_url));
$path = str_replace($where, '', $request_url);
$auto_cancel = $path . "ff/p/" . $p;
$this->curl_request($auto_cancel); //异步内循环
}
$res = Db::table("users_account_copy")->order("user_id asc")->limit($limit)->select();
if (empty($res)) {
$this->error("Not data end.");
}
// $model = new \app\member\model\AccountModel();
$accout_log = new \app\member\model\AccountLogModel();
// $usermod=new \app\member\model\UsersModel();
//数据处理
foreach ($res as $val) {
//用户更新数据
$sql = "update users_account set balance_money=balance_money+" . $val['balance_money2'] . ",use_integral=use_integral-" . $val['use_integral']
. " where user_id = " . $val['user_id'];
Db::query($sql);
$data=Db::table("users_account")->where("user_id",$val['user_id'])->find();
//用户日志记录写入
$insert = [
"old_total_dividend" => $data['total_dividend'],
"total_dividend" => $data['total_dividend'],
"total_integral" => $val['use_integral'],
"old_total_integral" => $val['use_integral']+$data['use_integral'],
"balance_money" => $val['balance_money2'],
"old_balance_money" => $data['balance_money']-$val['balance_money2'],
"use_integral" => $val["use_integral"],
"old_use_integral" => $val['use_integral']+$data['use_integral'],
"change_time" => time(),
"change_ip" => request()->ip(),
"change_desc" => "快乐豆转余额",
"change_type" => 3,
"detail_type" => 0,
"user_id" => $val['user_id'],
// "by_id"=>2,
];
$res2 = $accout_log->add_log($insert);
if($res2<=0){
data_log($insert, "ff_err.txt");
}
}
}
function test() {
echo "<xmm>1";
echo $this->curl_request();
}
}
Pss:有些懒,给自己一个放纵的理由,懒人有懒福。