我有个像外部服务器下单的问题想请教下

hahabudai

想请教下@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']);
                }
            }
        });
    }

}
1388 0 0
0个回答

年代过于久远,无法发表回答
🔝