Timer Server in ReactPHP

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:

  • GET /timers - list the active timers

  • POST /add - add a timer, and returns a timer index for future reference

  • 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($task, 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();