0

If some condition is met, how can I make the function:

  1. Stop executing the rest of the function
  2. Wait X time
  3. Restart the function

Would it be something like:

function someFunc() {
    if (x == 0) {
        sleep(60);
        someFunc();
        return;
    }
    ...other code only to be run if above is false...
}
someFunc();

...other code only to be run if above function finishes running completely...

In case its relevant and there is some library to handle APi limits or something, I am doing this for an API connection. First I receive a webhook hit via

file_get_contents('php://input')

which contains a URL. Then I hit the URL with

file_get_contents( $url )

and, after parsing $http_response_header into a $headers array, check it's header as if ($header['api_limit'] == 0) ... (in the above example this is x). If "x" is 0, then I want the function to wait a minute until the limit cycle resets and run the second file_get_contents( $url ) and the parsing that follows it again.

The main reason I wanted to handle it this way is to not have to record anything. The webhook I receive via file_get_contents('php://input') only happens once. If API rate limit is hit and I try to use the URL in the webhook but fail, then the URL is lost. So I was hoping the function would just wait X time until the rte resets until trying to use the webhook-received URL with file_get_contents($url) again. Is this bad practice somehow?

Andre Bulatov
  • 1,090
  • 3
  • 16
  • 47
  • As opposed to setting up a logical storage and cron processing script? – Kai Qing Jul 28 '16 at 01:15
  • That sounds rough and a bit complex, no? Is the method I'm suggesting bad memory wise or for some other reason? – Andre Bulatov Jul 28 '16 at 01:19
  • The main reason I wanted to handle it this way is to not have to record anything. The webhook I receive via `file_get_contents('php://input')` only happens once. If API rate limit is hit and I try to use the URL in the webhook but fail, then the URL is lost. So I was hoping the function would just wait X time until the rte resets until trying to use the webhook-received URL with `file_get_contents($url)` again. Is this bad practice somehow? – Andre Bulatov Jul 28 '16 at 01:24
  • stick your function in an object and then use the structure of objects to do what you need pretty easily. – Martin Jul 28 '16 at 01:45
  • Are you trying to generate a [coroutine](http://stackoverflow.com/questions/553704/what-is-a-coroutine)? – Martin Jul 28 '16 at 01:47
  • @Martin, not sure how to do that. – Andre Bulatov Jul 28 '16 at 01:50
  • 1
    [also perhaps this will help](https://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html)? Coroutines on PHP seem to be very edge case at the moment judging by the literature. – Martin Jul 28 '16 at 01:50
  • @Martin, the coroutine sounds a bit too complex for my needs, but please correct me if I'm wrong. I basically need to keep hitting `file_get_contents($someUrl)` until it doesn't return a 429 response code. Once the code is not 429, then continue to handle the response. – Andre Bulatov Jul 28 '16 at 01:52

2 Answers2

2

With rate limited resources you usually want to cache a copy of the data for blocks of X minutes so that the limit is never actually exceeded. For example, in the case of a maximum of 10 requests per hour you would cache the response for at least 6 minutes before attempting fetch a new response.

It is not a good idea to stall the entire PHP interpreter until the rate limit is lifted.

As for approaching "repeat an attempt to do something until it works" in general, this is not something that PHP handles very well given you usually want a request and response cycle with PHP to be as fast as possible so it can move onto the next request. Your PHP application should provide an immediate yes/no response to an external utility that triggers the task at a given interval.

Marty
  • 39,033
  • 19
  • 93
  • 162
  • Wait, you mean if a webhook hits some script at `http:/api.myserver.com/parser-script.php`, and if that scripts execution is stalled by something like `sleep();` or just recursion, then it can't receive another webhook until the first script initialization finishes? – Andre Bulatov Jul 28 '16 at 02:09
  • 1
    @AndreBulatov You can get more information about that particular query [here](http://stackoverflow.com/questions/1430883/simultaneous-requests-to-php-script). The most notable bit from my perspective is that *requests from the same client are queued*, so whichever client you use to wait for the rate limit will be unable to interact with other parts of your PHP application until it's successful. – Marty Jul 28 '16 at 02:10
  • ah, so first answer is "WordPress, doh!" But what's the client in this case? This is super enlightening and yet it doesn't seem to really pose an obstacle for my method. I'll only be receiving about 100-200 webhook per day, most within 1 hour, at around say 11am. The rate limit is 40 per minute. So, it'll parse 40, hang while it queues any other incoming POSTs, as soon as limit is reset, it'll do the same 1 or two more times, and done. Would this be bad if I can anticipate a small set number of POSTs to the script? – Andre Bulatov Jul 28 '16 at 02:19
1

I solved it like this:

// This will be the testing variable, where in the actual script
// we'll check the response code of file_get_contents 
$count = 0;

function funcTwo( &$count ) {

    // Here I'd run file_get_contents and parse the headers
    $count = ++$count;
    echo "functTwo() running $count... \n";             

    // Here I'll test for response code 429, if true, restart
    if ($count !== 5) {
        echo "Count only = $count so we're gonna take a nap... \n";
        sleep(1);           
        echo "Waking from sleep $count and rerunning myself... \n";
        funcTwo($count);
        return;
    }

    echo "Count finally = $count, exiting funcTwo... \n";

}

// This function does the main work that relies on the successful response from 
function funcOne( $count ) {

    echo "functOne() running! \n";

    // The function will be delayed here until a successful response is returned
    funcTwo($count);

    echo "Count finally = $count, so now we can finally do the work that \n";
    echo "depends on a successful response from funcTwo() \n";

    // Do main work

    echo "Work done, exiting funcOne and script... \n";

}

funcOne($count);
Andre Bulatov
  • 1,090
  • 3
  • 16
  • 47