PHP

Timer Server in ReactPHP

Sand Clock
Photo by nile on Pixabay

In many applications such as auctions, you need a dynamic collection of timers, such that you can add timers, and cancel timers.

We found ReactPHP superior for this. This sweet and simple server sets a new timer specified by a timeout and a task to be performed on timeout. For example sake, the task is just a string to be printed.

The server has three endpoints:

  • 1. GET /timers - list the active timers
  • 2. POST /add - add a timer, and returns a timer index for future reference
  • 3. POST /cancel - delete a timer by its index

Assuming you have installed ReactPHP using:

composer install react/event-loop
composer install react/http
Composer install nikic/fast-route

The server is:

require __DIR__ . '/vendor/autoload.php';
use React\Http\Server;
use React\Http\Response;
use React\EventLoop\Factory;
use Psr\Http\Message\ServerRequestInterface;

$counter = 0;
$timers = [];

$loop = Factory::create();

$server = new Server(function (ServerRequestInterface $request) use (&$timers, &$loop, &$counter) {
  $path = $request->getUri()->getPath();
  $method = $request->getMethod();
  if ($path === '/timers' && $method === 'GET') {
    return new Response(200, ['Content-Type' => 'text/plain'],  implode(PHP_EOL, $tasks));
  } else if ($path == '/add' && $method === 'POST') {
    var_dump($request->getParsedBody());
    $task = $request->getParsedBody()['task'] ?? null;
    if ($task) {
      $timer = $loop->addPeriodicTimer($time, function() use(&$task) { 
        echo "task:" . $task . "Timeout \n"; 
      });
              $timers[$counter++] = $timer;
      return new Response(201, $counter);
    }
    return new Response(400, ['Content-Type' => 'text/plain'], 'Task field is required');
  } else if ($path === '/cancel' && $method === 'POST') {
    $index = $request->getParsedBody()['index'] ?? null;
    if ($index) {            
      $loop->cancelTimer($tasks[$index]);
    }
    return new Response(201);
  }
  return new Response(404, ['Content-Type' => 'text/plain'],  'Not found');
});

$socket = new \React\Socket\Server('127.0.0.1:8000', $loop);
$server->listen($socket);

echo 'Listening on ' . str_replace('tcp:', 'http:', $socket->getAddress()) . "\n";
$loop->run();

Yoram Kornatzky

Yoram Kornatzky