Swoole是如何实现任务定时自动化服务器的?

开发环境

环境: lnmp下进行试验

框架: laravel5

问题描述:

这几天做银行对账接口时,踩了一个坑,具体需求大致描述一下。

银行每天凌晨后,会开始准备昨天的交易流水数据,需要我们这边请求拿到数据。

因为他们给的是base64加密的aip压缩流,解开以后可以得到txt文件,里面就是我们需要的数据了。

业务程序写好以后,部署了一个定时任务,第二天才发现并没有拿到数据,查询了一下日志的时候

发现,凌晨服务端请求的时候,银行接口返回了:系统错误信息

咨询银行那边后,银行那边相关工作人建议我们多请求几次,但是在对多次请求中,我们发现

银行那边是有频率限制的,最后得知,此接口只能半个小时请求一次,这就比较尴尬了,因为我不知道银行那边什么

时候等返回数据给我,于是这个问题怎么解决呢?理想的情况是,服务端请求数据,银行那边没有返回,房后程序等

半个小时后,再请求一次,这样一直到樱银行那边返回正确的数据中止。

问题分析:

这个功能可以搭配linux下的cron来实现,比如我们可以再凌晨到6:00之前做一个定时任务,每半个小时扫描一次脚本

如果发现银行那边的状态依旧为失败的话,我们就执行一次php脚本去请求数据,直到请求到正确的数据,然后把状态

更新为成功,这不失为一种方式,但太傻,比如说银行那边比较正常,凌晨,也就是第一次请求的时刻就返回了正确的

数据,那么我们的cron脚本还傻傻的每个半个小时执行一次,也可以使用linux下的at命令

解决问题:

在这里我们使用swoole的定时任务来处理

swoole客户端,用于触发定时任务   普通的类

<?php
namespace App\Exceptions\php;

class swoole
{
    private $data;
    private $client;

    public function __construct($data){
        $this->data = $data;
        $this->client = new \swoole_client(SWOOLE_SOCK_TCP);
    }
    public function connect(){
        if( !$this->client->connect("127.0.0.1", 9501 , 1) ) {
            echo "Error";
        }
        $this->client->send($this->data);
    }

}

swoole服务端,用于被调用设置定时任务  Laravel控制台命令

<?php

namespace App\Console\Commands;


use Illuminate\Console\Command;

class swoole extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'swoole {action}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = "Let's use swoole !";

    private $serv;

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //执行相应的操作
        $arg = $this->argument('action');
        switch ($arg) {
            case 'start':
                $this->info('swoole server started');
                $this->start();
                break;
            case 'stop':
                $this->info('stoped');
                $this->stop();
                break;
            case 'restart':
                $this->info('restarted');
                break;
        }
    }

    //启动服务器
    private function start()
    {
        $this->serv = new \swoole_server("127.0.0.1", 9501);
        $this->serv->set(array(
            'worker_num' => 8,
            'daemonize' => false,
            'max_request' => 10000,
            'dispatch_mode' => 2,
            'task_worker_num' => 8,
            'task_ipc_mode' => 3,
            'log_file' => storage_path('logs/taskqueue.log'),
        ));
        //统一绑定事件回调
        $this->serv->on('Receive', array($this, 'onReceive'));
        $this->serv->on('Task', array($this, 'onTask'));
        $this->serv->on('Finish', array($this, 'onFinish'));
        //启动服务器
        $this->serv->start();

    }

    //接收到客户端发送的消息
    public function onReceive(\swoole_server $serv, $fd, $from_id, $data)
    {
        //投递任务
        $serv->task($data);
    }

    //接收到任务
    public function onTask($serv, $task_id, $from_id, $data)
    {
        echo '任务来了';
        $timeon = (3) * 1000;
        if ($timeon > 0) {
            //定时器 3秒后执行
            $serv->after($timeon, function () {
                //业务逻辑处执行相应的业务命令   注意换成对应的路径
                exec('php /Volumes/Mac/Project/PHP_TEST/hisLaravel/artisan Test:Command');
            });
        }
    }
    //任务执行完毕
    public function onFinish($serv, $task_id, $data)
    {

        //echo "Task finish\n";
        echo '任务执行完毕';
    }

    //关闭所有的php进程
    private function stop()
    {
        exec('/usr/bin/killall php');
    }

}

业务脚本  Laravel控制台命令

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class TestCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'Test:Command';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command Test';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //这里是业务逻辑
        //如果银行那边返回的为false的话,那么我们把他交给swoole的定时脚本
        $status = false;
        $num = rand(1,2);
        //判断是否再次进行调用
        if($num!==1)
        {
            $swoole = new \App\Exceptions\php\swoole("hehe");
            $swoole->connect();
        }else{
            echo '获取到数据';
            echo $num;
        }
        
    }

}

流程总结:

1.启动服务器  php artisan swoole start   ->  

2.使用Linux定时器固定每个时间执行业务脚本  php artisan Test:Command   ->

3.如果业务执行失败(如果业务执行成功,那么不需要再执行后续操作) ,实例化swoole客户端给swoole发送消息,设置定时器  ->

4.服务器定时器xx秒后再次调用业务脚本 php artisan Test:Command 如果执行失败则回到3流程


MyAnswer博客

MyAnswer博客
请先登录后发表评论
  • 最新评论
  • 总共0条评论