0

I am trying to run EvPeridoc to log data periodically (every 15 minutes, i.e 900 seconds) to a file.

<?php
$tolog = '';
$w = new EvPeriodic(fmod(Ev::now(), 900), 900, NULL, function($w, $revents)
{
    file_put_contents("log.txt", $tolog . PHP_EOL, FILE_APPEND | LOCK_EX);
});
Ev::run(Ev::RUN_NOWAIT);
echo "Started periodic @ " . date("Y-m-d h:i:sa") . PHP_EOL;
for (;;) {
    $tolog = "Update @ " . date("Y-m-d h:i:sa");
}

The periodic never fires but the app goes into the for loop. If I change the line Ev::run(Ev::RUN_NOWAIT); to Ev::run(); then the script never reaches the loop.

So the question is how do I pipe this code to be able to fire logging routine every 15 mins?

EDIT: Just to clarify - the infinite loop at the end of this script generates the data to be logged (and assigns the value to the $tolog gloabl variable). What I'd like EvPeriodic to do is pick up that (global) variable every 15 minutes and append it to a file.

Nepaluz
  • 669
  • 1
  • 12
  • 27
  • 1
    Why are you using both EvPeriodic along with an infinite loop? I'm pretty certain that the infinite loop is blocking the re-entry of the event loop, and I don't know why it needs to exist in the first place. Basically, if you are using EvPeriodic, you should do everything in the loop, or use additional EvPeriodic if really needed. – Chris Haas Apr 13 '21 at 13:47
  • The reason I run an infinite loop is because it (should) contain(s) the logic for computing and generating the data that need to be logged every 15 mins. This is then assigned to the (global?) variable $tolog from where the periodic loop then logs to file. (an aside, the code above is not able to access $tolog but that is an aside). – Nepaluz Apr 13 '21 at 14:55
  • 1
    To access that variable as a non-global, you should be able to capture it with `use ($tolog)`. But I still don't think that EvPeriodic can run an interupt into something that isn't async already, and native PHP code isn't async. If you really want to do this, I think you might have to look into Fibers or AMP or similar. I will admin, however, that I'm not an expert with EvPeriodic, so I could be wrong, too. – Chris Haas Apr 13 '21 at 15:23
  • @ChrisHaas - I think you are right, I just couldn't get it to run whichever which way I tried. Placing either loop inside the other simply convolutes the intended logic. By-the-way, I cannot get the periodic to run at all with RUN_NOWAIT but it runs with RUN_ONCE ... – Nepaluz Apr 13 '21 at 15:27

1 Answers1

0

As per comments to the question, it is not possible to use both an infinite loop (which in my production app is a streaming http loop) and Evperiodic. I worked around this by using IPC and ended up by having to run the EvPeriodic code in a separate script.

Main app

<?php
$socket  = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($socket, '127.0.0.1', 15000);
socket_listen($socket);
socket_set_nonblock($socket);
$tolog= '';
for (;;){
        $tolog = "Update @ " . date("Y-m-d h:i:sa");
        if (($newc = socket_accept($socket)) !== false) {
                socket_write($newc, $tolog, strlen($tolog));
                socket_close($newc);
        }
}

The 'client' app with EvPeriodic polling the main app

<?php
$w = new EvPeriodic(fmod(Ev::now(), 15), 15, NULL, function($w, $revents){
        $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        socket_connect($sock, '127.0.0.1', 15000);
        $line = trim(socket_read($sock, 1024));
        file_put_contents("/var/log/cohocompanies.log", $line . PHP_EOL, FILE_APPEND | LOCK_EX);
        socket_close($sock);
});
Ev::run();
Nepaluz
  • 669
  • 1
  • 12
  • 27