想请教下@walkor大神和各位大大。
我这边有个需求是这样的:
我们需要向外部服务器下订单。他们下单时间是固定的(晚上的11点到12点)。并且只提供给我们一个连接。而且需要登录并且维持长连接。否则这个时间点就非常难连上了。因为调他们接口的不止我们一家。他们应该也有限制。
我们是白天统计从11点到12点 每秒需要下单的数据。然后放入REDIS。
我们的数据类似这样:
2021-08-10 11:00:00 [ ['id'=>100,'num'=>3], ['id'=>101,'num'=>3]]
2021-08-10 11:00:01 [ ['id'=>200,'num'=>1]]
我现在的处理是 连接成功后登录成功后 就获取这些数据。比如现在是11:00:00。这个时候我会获取[ ['id'=>100,'num'=>3], ['id'=>101,'num'=>3]]然后发给他们下单。他们给我返回后我再次获取然后再次发送。那就有一个问题。第一他们返回很快 就等于返回的时候还是11:00:00。那么我会再发一次。这个没关系。因为他们是有库存的而且是在11:00:00到11:00:01中间放出,但是具体时间不告知。也就是我们不一定能抢得到单。
现在的问题就出在 如果他们响应慢了,比如几秒后他才能响应。那么这几秒我们一直在等他的响应。不会获取订单也不会发送,也就导致这几秒的订单是根本连下都没下。下也没用了 因为肯定抢不到。导致的结果就是连发都没发。所以等于这几秒的订单压根不可能抢到
我试过解决这个问题就是不等他响应继续发。我感觉他们程序应该是做过处理。就是比如我 请求1延时了,那么再发请求2 他依然不会给我返回直到缓冲区满。
现在这个问题搞的我很头疼,完全没思路了。想问下有没有什么好的建议或者解决方法。
我的代码如下:
<?php
use \Workerman\Lib\Timer;
use \Workerman\Connection\AsyncTcpConnection;
class Order
{
private $wbser;
private $islogin=false;
private $sendtime=0;
private $redis;
public function __construct(){
$this->redis=libredis::instance();
}
//像外部服务器发送
private function _send($data){
$this->sendtime=time();
$data=is_array($data) ? json_encode($data) : $data;
$this->wbser->send($data);
}
//从外部服务器接收
private function _recv($data){
$data=json_decode($data);
if($data['action']=='login' && $data['code']==200){
$this->islogin=true;
$this->_getorder();
}elseif($data['action']=='order' && $data['code']==200){
//处理下单逻辑
$this->redis->set("order:set_{$data['time']}",$data['data']);
//下单完成 继续获取
$this->_getorder();
}
}
//获取要下单的数据
private function _getorder(){
//按时间获取要下单的数据
$time=date('Y-m-d H:i:s');
$data = $this->redis->get("order:get_{$time}");
//不管有没有都给他发
$this->_send(['action'=>'order','order'=>$data,'time'=>$time]);
}
//开启
public function serverOnStart()
{
$context_option = [
'ssl' => [
'local_cert' => SSL_CERT_PATH,
'passphrase' => '',
'allow_self_signed' => true,
'verify_peer' => false,
'verify_peer_name' => false,
]
];
//连接外部服务器
$this->wbser = new AsyncTcpConnection(HOST,$context_option);
$this->wbser->onConnect = function($connect)
{
//连接上后登陆
$data=['action'=>'login','username'=>'xxx','password'=>'xxx'];
$this->_send($data);
$this->_hreatbeat();
};
$this->wbser->onMessage = function($connect, $data)
{
$this->_recv($data);
};
$this->wbser->onClose = function()
{
$this->islogin=false;
};
$this->wbser->connect();
}
private function _hreatbeat(){
Timer::add(60,function()
{
if($this->islogin==true){
$space=time()-$this->sendtime;
if($space>240){
//超过4分钟发送心跳
$this->_send(['action'=>'hreatbeat']);
}
}
});
}
}