关于Crontab结合http-client使用疑问

jiaruo

问题描述

需要3秒请求一次 API接口,不管3秒内是否请求到,必须在上一次请求的3秒后再次发出请求。

理想结果

第1次请求--------2024-06-03 01:32:28
第2次请求--------2024-06-03 01:32:31
第3次请求--------2024-06-03 01:32:34
第4次请求--------2024-06-03 01:32:37


为此你搜索到了哪些方案及不适用的原因

目前使用的是Crontab结合异步请求。
疑问:请问大佬们,这种方案会出现什么异常,如:连接过多或者跑满内存等问题?

代码1如下

<?php
use Workerman\Worker;
require __DIR__ . '/vendor/autoload.php';

use Workerman\Crontab\Crontab;
$worker = new Worker();

// 设置时区,避免运行结果与预期不一致
date_default_timezone_set('PRC');

$worker->onWorkerStart = function () {
    // 每分钟的第1秒执行.
    $http = new Workerman\Http\Client();

    new Crontab('*/3 * * * * *', function() use ($http){
        $http->request('https://www.workerman.net', [
            'method' => 'POST',
            'version' => '1.1',
            'headers' => ['content-type' => 'application/json','Connection' => 'keep-alive'],
            'data' => json_encode(['detail' => true]),
            'success' => function ($response) {
                $result = $response->getBody();
                $result = json_decode($response->getBody(),true);
                    echo date('Y-m-d H:i:s')."\n";
            },
            'error' => function ($exception) {
                echo $exception;
            }
        ]);
    });
};

Worker::runAll();

代码2如下

<?php
use Workerman\Worker;
use Workerman\Timer;
require_once __DIR__ . '/vendor/autoload.php';

//发送请求
function request($http)
{

    $http->request('https://www.workerman.net/', [
            'method' => 'POST',
            'version' => '1.1',
            'headers' => ['content-type' => 'application/json','Connection' => 'keep-alive'],
            'data' => json_encode(['detail' => true]),
            'success' => function ($response) {
                $result = $response->getBody();
                $result = json_decode($response->getBody(),true);
            },
            'error' => function ($exception) {
                echo $exception;
            }
        ]);
}

$task = new Worker();
// 开启多少个进程运行定时任务,注意业务是否在多进程有并发问题
$task->count = 1;
$task->onWorkerStart = function(Worker $task)
{
    $http = new Workerman\Http\Client();
    Timer::add(3, 'request',[$http],true);
};

// 运行worker
Worker::runAll();
238 2 0
2个回答

小Z先生

那你不应该使用定时器 应该使用Timer::add() persistent参数传false;

$worker->onWorkerStart = function () {

    $cb = function()use(&$cb){
     $http = new Workerman\Http\Client();
     $http->request('https://www.workerman.net', [
            'method' => 'POST',
            'version' => '1.1',
            'headers' => ['content-type' => 'application/json','Connection' => 'keep-alive'],
            'data' => json_encode(['detail' => true]),
            'success' => function ($response) {
                $result = $response->getBody();
                $result = json_decode($response->getBody(),true);
                    echo date('Y-m-d H:i:s')."\n";

                Timer::add(3,$cb,[],false);
            },
            'error' => function ($exception) {
                echo $exception;
                Timer::add(3,$cb,[],false);
            }
        ]);
    }
    $cb();
};

Worker::runAll();

我是这样想的,你可以尝试一下是否能够满足需求,我并没有实际使用过这种方式
这段代码的意思就是请求后3s后再次执行$cb方法,persistent-false表示定时器不循环执行,就是执行一次的意思

  • jiaruo 17天前

    如果按照这样说,请求成功后才会Timer::add,如果请求返回结果为2秒,加上定时器的3秒 那么第一次请求和第二次请求就是5秒了

  • 小Z先生 17天前

    这个你可以自己进行计算的嘛 比如开始获取一下$start = time() 然后请求后获取一下time()-$start

    if(time()-$start >=3){
        Timer::add(0.001,$cb,[],false); //直接执行下一次
    }else{
        Timer::add(3-(time()-$start),$cb,[],false); //执行下一次
    }
  • jiaruo 17天前

    这样还是不能保证3秒执行,如果请求时间超过5秒了就嘎了

  • 小Z先生 17天前

    如果一定的3s执行 那就不管http请求呗 反正Workerman\Http\Client本来就是异步的
    你就Timer::add(3,$cb) 发送一个请求就完了 不管请求执行了几秒

  • jiaruo 17天前

    OK 好的 我尝试一下 感谢

  • 小Z先生 17天前

    那其实你现在的逻辑并没问题,就是3s发送一次请求嘛 Workerman\Http\Client是异步的 又不管时间,我理解错了题意思,我以为是请求后才能在发送下一个请求

  • jiaruo 17天前

    麻烦帮我看下代码2是否有问题,目前测试执行效果和代码1是一致

jeyfang

这里为啥不直接Timer::add(3, fn),然后fn去异步处理

  • jiaruo 17天前

    使用定时器结合http-client吗?或者说我现在的方案是有什么问题

  • jeyfang 17天前

    没看出有啥问题,但要是我的话就选方案二了,在webman里面有Timer了就直接用了

  • jiaruo 17天前

    好来哥。我听你的

🔝