Giter Club home page Giter Club logo

event-loop's Introduction

ReactPHP Logo

Event-driven, non-blocking I/O with PHP.

Build Status

ReactPHP is a low-level library for event-driven programming in PHP. At its core is an event loop, on top of which it provides low-level utilities, such as: Streams abstraction, async DNS resolver, network client/server, HTTP client/server and interaction with processes. Third-party libraries can use these components to create async network clients/servers and more.

<?php

// $ composer require react/http react/socket # install example using Composer
// $ php example.php # run example on command line, requires no additional web server

require __DIR__ . '/vendor/autoload.php';

$server = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) {
    return React\Http\Message\Response::plaintext(
        "Hello World!\n"
    );
});

$socket = new React\Socket\SocketServer('127.0.0.1:8080');
$server->listen($socket);

echo "Server running at http://127.0.0.1:8080" . PHP_EOL;

This simple web server written in ReactPHP responds with "Hello World!" for every request.

ReactPHP is production ready and battle-tested with millions of installations from all kinds of projects around the world. Its event-driven architecture makes it a perfect fit for efficient network servers and clients handling hundreds or thousands of concurrent connections, long-running applications and many other forms of cooperative multitasking with non-blocking I/O operations. What makes ReactPHP special is its vivid ecosystem with hundreds of third-party libraries allowing you to integrate with many existing systems, such as common network services, database systems and other third-party APIs.

  • Production ready and battle-tested.
  • Rock-solid with stable long-term support (LTS) releases.
  • Requires no extensions and runs on any platform - no excuses!
  • Takes advantage of optional extensions to get better performance when available.
  • Highly recommends latest version of PHP 7+ for best performance and support.
  • Supports legacy PHP 5.3+ and HHVM for maximum compatibility.
  • Well designed and reusable components.
  • Decoupled parts so they can be replaced by alternate implementations.
  • Carefully tested (unit & functional).
  • Promotes standard PSRs where possible for maximum interoperability.
  • Aims to be technology neutral, so you can use your preferred application stack.
  • Small core team of professionals supported by large network of outside contributors.

ReactPHP is non-blocking by default. Use workers for blocking I/O. The event loop is based on the reactor pattern (hence the name) and strongly inspired by libraries such as EventMachine (Ruby), Twisted (Python) and Node.js (V8).

This repository you're currently looking at is mostly used as a meta repository to discuss and plan all things @ReactPHP. See the individual components linked below for more details about each component, its documentation and source code.

Core Components

Network Components

Utility Components

Built with ReactPHP

  • Thruway PHP Client and Router Library for Autobahn and WAMP (Web Application Messaging Protocol) for Real-Time Application Messaging voryx/Thruway

  • PPM - PHP Process Manager PPM is a process manager, supercharger and load balancer for modern PHP applications. php-pm/php-pm

  • php-ar-drone 🚁 Port of node-ar-drone which allows user to control a Parrot AR Drone over PHP jolicode/php-ar-drone

  • Ratchet Asynchronous WebSocket server ratchetphp/Ratchet

  • Predis\Async Asynchronous PHP client library for Redis built on top of ReactPHP nrk/predis-async

  • clue/redis-server A Redis server implementation in pure PHP clue/redis-server

And many more on our wiki page »

Articles

  • Sergey Zhuk A series of articles covering ReactPHP: from the basics to the real application examples. sergeyzhuk.me

  • Cees-Jan Kiewiet Blog series about several ReactPHP components and how they work. blog.wyrihaximus.net

  • Loïc Faugeron Super Speed Symfony - ReactPHP. gnugat.github.io

  • Marc J. Schmidt Bring High Performance Into Your PHP App (with ReactPHP). marcjschmidt.de

  • Marc Morera When ReactPHP meet Symfony medium.com/@apisearch

Talks

Getting started

ReactPHP consists of a set of individual components. This means that instead of installing something like a "ReactPHP framework", you actually pick only the components that you need.

This project follows SemVer for all its stable components. The recommended way to install these components is through Composer. New to Composer?

For example, this may look something like this:

# recommended install: pick required components
composer require react/event-loop react/http

As an alternative, we also provide a meta package that will install all stable components at once. Installing this is only recommended for quick prototyping, as the list of stable components may change over time. This meta package can be installed like this:

# quick protoyping only: install all stable components
composer require react/react:^1.4

For more details, check out ReactPHP's homepage for quickstart examples and usage details.

See also the combined changelog for all ReactPHP components for details about version upgrades.

Support

Do you have a question and need help with ReactPHP? Don't worry, we're here to help!

As a first step, check the elaborate documentation that comes with each component (see links to individual documentation for each component above). If you find your question is not answered within the documentation, there's a fair chance that it may be relevant to more people. Please do not hesitate to file your question as an issue in the relevant component so others can also participate.

You can also check out our official Gitter chat room. Most of the people involved in this project are available in this chat room, so many questions get answered in a few minutes to some hours. We also use this chat room to announce all new releases and ongoing development efforts, so consider staying in this chat room for a little longer.

Also follow @reactphp on Twitter for updates. We use this mostly for noteworthy, bigger updates and to keep the community updated about ongoing development efforts. You can always use the #reactphp hashtag if you have anything to share!

We're a very open project and we prefer public communication whenever possible, so that more people can participate and help getting the best solutions available. At the same time, we realize that some things are better addressed in private. Whether you just want to say thank you, want to report a security issue or want to help sponsor a certain feature development, you can reach out to the core team in private by sending an email to [email protected]. Please keep in mind that we're a small team of volunteers and do our best to support anybody reaching out.

Do you want to support ReactPHP? Awesome! Let's start with letting the the world know why you think ReactPHP is awesome and try to help others getting on board! Send a tweet, write a blog post, give a talk at your local user group or conference or even write a book. There are many ways you can help. You can always reach out to us in private and help others in our support channels. Thank you!

Tests

To run the test suite, you first need to clone this repo and then install all dependencies through Composer:

composer install

To run the test suite, go to the project root and run:

vendor/bin/phpunit

The test suite also contains a number of functional integration tests that rely on a stable internet connection. Due to the vast number of integration tests, these are skipped by default during CI runs. If you also do not want to run these, they can simply be skipped like this:

vendor/bin/phpunit --exclude-group internet

License

MIT, see LICENSE.

event-loop's People

Contributors

cameronjacobson avatar carusogabriel avatar cboden avatar cebe avatar clue avatar dandelionred avatar e3betht avatar greevex avatar igorw avatar ivkalita avatar jmalloc avatar jsor avatar kelunik avatar kooldev avatar lcobucci avatar lt avatar lucasnetau avatar mkrauser avatar nawarian avatar nhedger avatar nrk avatar ocramius avatar ondrejmirtes avatar pablokowalczyk avatar pborreli avatar reedy avatar seregazhuk avatar simonfrings avatar steverhoades avatar wyrihaximus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

event-loop's Issues

Multiple function calls asynchronously

Hi ! I need to execute multiple calls to same function asynchronously. I have 2 projects (project1 and project2):

Project 1:

/**
* Loop an array of urls and call sub function.
**/
public function startFunction() {
  $finalResponse = [];
  $urls = ['www.google.es', 'www.github.com', 'www.bitbucket.org'];

  foreach ($urls as $url) {
    $res = $this->subFunction($url);    // subfunction call ( **IT MAY TAKE A LONG TIME !!** )
    $finalResponse[] = $res;
 }

 return $finalResponse;
}
/**
* Uses Factory loop to get the Promise returned by finalRequest function.
**/
private function subFunction($url) {
  $loop = \React\EventLoop\Factory::create();
  $classA = new Project2\ClassA();
  $finalResponse = null;

  // project 2 function call
  $classA->finalRequest($url)->then(function($response) use(   
     &$finalResponse
  ) {
     $finalResponse = $response;
  })
  
  return $finalResponse;
}

Project 2:

/**
* Makes an React\HttpClient request (GET) to sent url and return his value inside a Promise.
**/
public function finalRequest($url) {
   $generalDeferred = new Deferred();
   $generalPromise = $generalDeferred->promise();

   // make React\HttpClient request
   $request = $client->request('GET', $url);
   $request->on('response', function ($response) use($generalDeferred) {
   $response->on('data', function ($response) {
        $generalDeferred->resolve($response);
      });
   });
  $request->end();

  return $generalPromise;
}

Problem is that on every subFunction($url) call, the program stops until the sub Function gets the response, but I need to do this asynchronously because this subFunction could take many seconds.
So I would like to launch all subFunction($url) calls at the same time, and get all responses asynchronously.

It's possible solve this problem? Thanks.

Test failing depending o Kernel and OS configurations

Hi, all!

I was running the tests at my local environment because I wanted to improve somethings and I like to start by making sure everything is running properly ^^
Thing is that the test \React\Tests\EventLoop\AbstractLoopTest::testRemoveReadAndWriteStreamFromLoopOnceResourceClosesOnEndOfFileEndsLoop is failing for all implementations with the following message:

fwrite(): send of 8192 bytes failed with errno=35 Resource temporarily unavailable

This happens at line 231, which runs this: fwrite($other, str_repeat('.', 60000));

I did some basic research and looks like Mac OS can have very low values for buffer sizes, but changing those values via sysctl didn't take much effect.

According to this errors list errno=35 Resource temporarily unavailable means kPOSIXErrorEAGAIN and according to here the EAGAIN error says that possibly it would work in further attempts (not desirable for unit testing) and can be caused because a) a resource could be doing a blocking operation and was set as non-blocking before, which is plausible because for both streams we call stream_set_blocking with false or b) due to a resource shortage, which for me would make sense with the sysctl stuff. Documentation says that maybe delaying certain operations would help.

I suppose this kind of error would be super hard to reproduce, but I have something else that may help:

nawarian@phoenix event-loop (master) $ sysctl -a | egrep "space|maxsockbuf"
kern.ipc.maxsockbuf: 8388608
net.local.stream.recvspace: 8192
net.local.stream.sendspace: 8192
net.local.dgram.recvspace: 4096
net.inet.tcp.sendspace: 131072
net.inet.tcp.recvspace: 131072
net.inet.udp.recvspace: 196724
net.inet.raw.recvspace: 8192
net.stats.sendspace: 2048
net.stats.recvspace: 8192

It might be possible to reproduce such error if you run something like sysctl -w variable.name=new-value using those keys and values. But again: I'm not sure.

Could also be useful:

nawarian@phoenix event-loop (master) $ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.12.6
BuildVersion:	16G1114

Oh yes, almost forgot: lowering the string length at fwrite($other, str_repeat('.', 60000)); solve the issue.

Call to undefined method in memory benchmark

kelunik@kelunik ❯ ~/GitHub/reactphp/event-loop ❯ 16:13:08 ❯ master
$ time php examples/95-benchmark-memory.php 
PHP Version:		7.2.0
Loop			React\EventLoop\StreamSelectLoop
Time			Fri, 22 Dec 2017 15:13:19 +0000
--------------------------------------------------
PHP Fatal error:  Uncaught Error: Call to undefined method React\EventLoop\Timer\Timer::cancel() in /home/kelunik/GitHub/reactphp/event-loop/examples/95-benchmark-memory.php:39
Stack trace:
#0 [internal function]: {closure}(Object(React\EventLoop\Timer\Timer))
#1 /home/kelunik/GitHub/reactphp/event-loop/src/Timer/Timers.php(99): call_user_func(Object(Closure), Object(React\EventLoop\Timer\Timer))
#2 /home/kelunik/GitHub/reactphp/event-loop/src/StreamSelectLoop.php(182): React\EventLoop\Timer\Timers->tick()
#3 /home/kelunik/GitHub/reactphp/event-loop/examples/95-benchmark-memory.php(59): React\EventLoop\StreamSelectLoop->run()
#4 {main}
  thrown in /home/kelunik/GitHub/reactphp/event-loop/examples/95-benchmark-memory.php on line 39

real	0m1,065s
user	0m0,127s
sys	0m0,012s

ExtEventLoop causes segfault for pg_socket() resources

How can I addReadStream to pg_socket?

I try the following code on PHP 7.0

$loop = React\EventLoop\Factory::create();
$connection = pg_connect("host=localhost port=5432 dbname=mary");
$socket = pg_socket($connection);
$loop->addReadStream($socket , function (){
  echo "READ EVENT\n";
});

pg_send_query($connection , "select * from authors;");
$loop->run();

The code works well when I choose Select But when I run code with Event extension I have Segmentation fault

More details on http://php.net/manual/en/function.pg-socket.php

Prioritizing events in the loop

I am just starting with react so my question might be dumb. Pardon me for that, but here it is:

I have a Socket server with React. The use case of this server is to receive objects from its clients (which would mostly be my own web app backend) and dispatch them to external services via standard APIs - like sending email, sending SMS, sending messages to slack channel, push notifications, etc.

I do something like this:

require_once 'autoload.php';
	use \App\Experiment\SenderService;

	/** @var \React\EventLoop\StreamSelectLoop $loop */
	$loop = React\EventLoop\Factory::create();
	$server = new React\Socket\Server($loop);

	$connectionPool = new \SplObjectStorage();

	$server->on('connection', function ($conn) use ($connectionPool, $loop) {
		$strDataRead = 'xyz';
		/** @var \React\Socket\Connection $conn */
		$conn->on('data', function ($data) use ($connectionPool, $conn, &$strDataRead) {
			$connectionPool->attach($conn);

			$obj = unserialize($data);
			
			$strDataRead = serialize($data);
		});


		$conn->on('end', function () use ($connectionPool, $conn, &$strDataRead, $loop) {
			$connectionPool->detach($conn);

			$loop->futureTick(function () use ($strDataRead) {
				SenderService\Dispatcher::Dispatch($strDataRead);
			});
		});
	});

	echo "Socket server listening on port 4000.\n";
	echo "You can connect to it by running: telnet localhost 4000\n";
	$server->listen(4000);
	$loop->run();

The problem here is that when I send burst connections to the server using another script, the initial 30-40 requests get queued up real fast and then the server slows down and starts accepting requests at only about 1 request per second and that is very slow and defeats the purpose of the very service that I am trying to create.

My understanding is that it stats ticking using the tick function:

public function tick()
    {
        $this->nextTickQueue->tick();

        $this->futureTickQueue->tick();

        $this->timers->tick();

        $this->waitForStreamActivity(0);
    }

And there, it waits for stream activity only after it has processed all the ticks. Since there are now about 30-40 requests queued up, it gets slow. (I might be wrong in my assumption; please tell me if I am).

I want to prioritize the incoming connections to the server over the dispatcher so that the service is always ultra responsive in accepting new requests and goes on dispatching when it gets the time. How do I do that?

No way to add data to a timer in StreamSelectLoop

LoopInterface.php

    public function addTimer($interval, $callback);
    public function addPeriodicTimer($interval, $callback);

StreamSelectLoop.php

    public function addTimer($interval, $callback);
    public function addPeriodicTimer($interval, $callback);

I need to add a timer with associated data to my loop. I can create my own Timer object, but I have no way to inject it into the list maintained in StreamSelectLoop

I can PR something, just not sure how you want to approach it.

[libevent] is currently not work in php7

It all start with:

/vendor/react/event-loop/LibEventLoop.php on line 34

After trying to make it work, it come to:

pecl/libevent requires PHP (version >= 5.3.0, version <= 6.0.0, excluded versions: 6.0.0), installed version is 7.0.1-2+deb.sury.org~wily+1

No valid packages found

Not sure if I report this here is right since it depend on libevent

Support reference / unreference of watchers

Are there any plans to support referencing / unreferencing watchers as discussed in async-interop/event-loop? It's quite helpful to exit the loop when no further watchers exist, but cache expiration watchers or similar "background" watchers prevent this. If a watcher can be unreferenced, the loop exits if only unreferenced watchers exist anymore, instead of any watchers. It would thus be possible to have a cache expiration watcher that regularly checks items in a list for expiration and deletes them without having it interfere with the loop exit behavior.

PHPUnit Test Fail, Windows 10, PHP 7

Not sure if this is known, trying to debug an issue elsewhere in React, so running the test suites on all installed components... Please ignore/close this issue if unhelpful/not required...

PHPUnit 4.8.32 by Sebastian Bergmann and contributors.

SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS  63 / 145 ( 43%)
SSSSSSSSSSSSSSSSSSSSSSS..SSSSSS...........................SSSSS 126 / 145 ( 86%)
SSSSSSSSSSSSSF.....

Time: 846 ms, Memory: 8.00MB

There was 1 failure:

1) React\Tests\EventLoop\Timer\StreamSelectTimerTest::testAddTimer
Expectation failed for method name is equal to <string:__invoke> when invoked 1 time(s).
Method was expected to be called 1 times, actually called 0 times.

FAILURES!
Tests: 145, Assertions: 44, Failures: 1, Skipped: 110.

Using version 0.4.2 (dev-master has this error along with another as shown below:

PHPUnit 4.8.32 by Sebastian Bergmann and contributors.

SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS  63 / 146 ( 43%)
SSSSSSSSSSSSSSSSSSSSSSS.SSSSSS............................SSSSS 126 / 146 ( 86%)
SSSSSSSSSSSSSFF.....

Time: 1.84 seconds, Memory: 8.00MB

There were 2 failures:

1) React\Tests\EventLoop\Timer\StreamSelectTimerTest::testAddTimer
Expectation failed for method name is equal to <string:__invoke> when invoked 1 time(s).
Method was expected to be called 1 times, actually called 0 times.

2) React\Tests\EventLoop\Timer\StreamSelectTimerTest::testAddPeriodicTimer
Expectation failed for method name is equal to <string:__invoke> when invoked 3 time(s).
Method was expected to be called 3 times, actually called 2 times.

FAILURES!
Tests: 146, Assertions: 44, Failures: 2, Skipped: 110.

StreamSelectLoop: Int overflow if the timer interval is big on 32-bit systems

if $this->getNextEventTimeInMicroSeconds() in StreamSelectLoop.php returns a float value greater than max int value, it will give you this error

stream_select(): The microseconds parameter must be greater than 0

This will happen if the next event interval is greater than 2148. Or, in other words you can't have a periodic timer with interval greater than 2148 seconds.

Workarounds: have a dummy periodic timer with interval less than 2148 seconds.

Make loop classes extendable

Hallo,
I currently working on an multi-processing library (https://github.com/RogerWaters/react-thread-pool) compatible with react. My problem is that I require some additional functionality on the loop classes and everything is private here. Best way will be to extend the loops and add the functions (afterForkParent, afterForkChild).
Would you prefer that I create an pull request with all the functions and variables protected within the classes, or would you prefer that I add those functions directly to the classes? The only alternative will be to reflect those classes and this will result in poor performance and bad readable code. Maybe anyone have another solution?

Thanks for your help
RogerWaters

Error in the "Usage" sample code

$loop = React\EventLoop\Factory::create();

$server = stream_socket_server('tcp://127.0.0.1:8080');
stream_set_blocking($server, 0);
$loop->addReadStream($server, function ($server) use ($loop) {
    $conn = stream_socket_accept($server);
    $data = "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nHi\n";
    $loop->addWriteStream($conn, function ($conn) use (&$data, $loop) {
        $written = fwrite($conn, $data);
        if ($written === strlen($data)) {
            fclose($conn);
            $loop->removeStream($conn);
        } else {
// ==========================================
            $data = substr($data, 0, $written);
// Shouldn't it be substr($data, $written) ?
// ==========================================
        }
    });
});

$loop->addPeriodicTimer(5, function () {
    $memory = memory_get_usage() / 1024;
    $formatted = number_format($memory, 3) . 'K';
    echo "Current memory usage: {$formatted}\n";
});

$loop->run();

Allow multiple IO callbacks or throw

Currently, multiple IO callbacks are ignored, only the first one will work. #86 fixes this to be consistent, but silently ignoring should be changed to either throw exceptions or call all handlers and not ignore them.

Priority issues with multiple timers

If you run the following code

$loop = \React\EventLoop\Factory::create();
     for ($counter = 1; $counter <= 5; $counter++) {

         echo "Counter before loop {$counter}\n";
         $loop->addTimer(0.001, function () use ($counter) {
             echo "Counter in loop {$counter}\n";
         });
     }

$loop->run();

You get this output

Counter before loop 1
Counter before loop 2
Counter before loop 3
Counter before loop 4
Counter before loop 5
Counter in loop 1
Counter in loop 5
Counter in loop 4
Counter in loop 3
Counter in loop 2

The counter within the loop should be in the same order as the counter before the loop.

It looks like the issue is with line 33 in Timers.php. It adds the interval to $this->getTime(), which doesn't change.

A simple fix is to replace getTime() with updateTime(), which works as expected, but I'm not sure it that causes issues anywhere else.

$scheduledAt = $interval + $this->updateTime();

Let me know if you don't think it'll cause any other issues and I'll submit a PR.

Possible of dealing with SignalEvent

Usually a script using event loop should be able to deal with signals. Instead of using pcntl functions, can we open up the support for SignalEvent?

However as the loop is declared as private, there is no way of implement that by using either timer or tick queue.

Any thought?

PHP Warning: stream_select(): 26 is not a valid stream resource

This occurs when you try to close a resource already sent to stream_select (I assume this would be the same for the other implementations).

A possible solution would be to add a entry point right before you start another "wait for stream to change" session so that you can execute a resource close avoiding those nasty warnings.

Also: "PHP Warning: stream_select(): No stream arrays were passed"

All happens in StreamSelectLoop.php on line 255

Remove misleading Composer suggest keywords

For example, if I have ext-ev installed, Composer still suggest installing ext-libevent while it's unclear from a consumer's perspective how much value this provides.

Note that #113 has improved the suggest keyword description for each extension somewhat, but I believe this is more an issue with how Composer suggests these dependencies and now really something that can be addressed in this package.

As an alternative, I suggest simply dropping the suggest keyword completely. Is much gained by having this in place? Instead, I would suggest updating our install instructions to detail why having either extension can be a good thing (under what circumstances anyway?).

1.0 release

Event loop 0.4 is very stable and there aren't any big BC breaks planned (maybe #30) so what is stopping us from putting a list of small things together we want in 1.0 and work towards that so we can tag 1.0 and push any major redesigns to 2.0?

how can I get out of the loop (futuretick)

Hi how can I get out of the loop (futuretick) correctly with a command, key or typing in the console

example code

function fooBar($loop) {
    return function () use ($loop) {
       // my code 

// end my code
sleep(1);
        $loop->futureTick(fooBar($loop));
    };
}

$loop->futureTick(fooBar($loop));
$loop->run();

As I exit this loop correctly and without a Ctrl + C program I interrupt the running program

addPeriodicTimer() blocks the execution of my code

Hi folks!

I have a code like this:

      if ($message->content == 'startrare') {
          $loop->run($timer);
      } 

When if = true, loop runs and my code stops executing. Acts like a traditional php while/foreach...

Loop code looks like this:

$loop = React\EventLoop\Factory::create();
$i = 0;
$timer = $loop->addPeriodicTimer(5, function() use (&$myvar0, $loop, &$myvar1, &$myvar2, &$myvar3) {
echo 'OK';
...

I receive 'OK' each 5 seconds, but other code after (or before) loop not working until loop stops :/

How to read response from smtp server?

I connecting to SMTP server. (alt1.gmail-smtp-in.l.google.com:25 for example)
How can i read response when i write $connection->write('HELO alt1.gmail-smtp-in.l.google.com');?

StreamSelectLoop:Timers added during stream events are not accurate

New timers are scheduled relative to a local time kept in the timers class, which is only updated when Timers::tick() is run. However, when there are no scheduled tick callbacks, StreamSelectLoop will wait until the next scheduled timer (or infinite, if there are none) for stream activity, which prevents Timers::tick() from being called regularly and updating its local time. If a new timer is added in response to a stream event, it will be shortened by whatever period of time was spent waiting for stream activity (or, if the new timer's length is shorter than was spent waiting, the timer will be resolved immediately).

I believe a potential solution is:

diff --git a/src/Timer/Timers.php b/src/Timer/Timers.php
index c183a63..bebe552 100644
--- a/src/Timer/Timers.php
+++ b/src/Timer/Timers.php
@@ -30,7 +30,7 @@ class Timers
     public function add(TimerInterface $timer)
     {
         $interval = $timer->getInterval();
-        $scheduledAt = $interval + $this->getTime();
+        $scheduledAt = $interval + microtime(true);

         $this->timers->attach($timer, $scheduledAt);
         $this->scheduler->insert($timer, -$scheduledAt);

I can provide example reproducing scripts if preferred.

Can addPeriodicTimer() run on absolute time intervals?

Can I tell addPeriodicTimer() to run on intervals, that are exactly 1 second apart?
Currently, if I run the following code, I get the following output:

$this->loop->addPeriodicTimer(1, function() {
    echo microtime(); 
});

Output:
0.37149400 1407178007
0.37158300 1407178008
0.37231200 1407178009
0.37331500 1407178010
0.37484600 1407178011
0.37504500 1407178012
0.37549600 1407178013
0.37581600 1407178014
0.37665200 1407178015
0.37732800 1407178016
0.37813900 1407178017
0.37861000 1407178018
0.37891700 1407178019
0.37892400 1407178020
0.37978700 1407178021
0.38012900 1407178022
0.38106900 1407178023
0.38199600 1407178024
0.38300500 1407178025
0.38403600 1407178026
0.38425800 1407178027
0.38606900 1407178028

Im guessing addPeriodicTimer() is acting as a recursive addTimer() and the bit of time it takes to run is responsible for the 'skew' in time of each iteration. Can you give me advice on how to make it run uniformly? Thank you.

LibEventLoop and large messages

I ran into an issue when sending messages that are larger than the bufferSize in Stream (4096).

It appears that if the size of the data in the underlying stream is larger than the buffer, handleData only gets called once. The data remains there until there is another read event triggered on the stream.

I wrote something to reproduce it:

<?php
require_once __DIR__ . "/vendor/autoload.php";

$loop = \React\EventLoop\Factory::create();

list($sockA, $sockB) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0);

$streamA = new \React\Stream\Stream($sockA, $loop);
$streamB = new \React\Stream\Stream($sockB, $loop);

$testString = str_repeat("*", $streamA->bufferSize + 1);

$i = 0;
$buffer = "";
$streamB->on('data', function ($data, $streamB) use (&$i, &$buffer, &$testString) {
    $i++;
    $buffer .= $data;
    echo "Call " . $i . ": " . strlen($data) . " bytes - buffer is " . strlen($buffer) . " bytes\n";
    if (strlen($testString) == strlen($buffer)) {
        $streamB->close();
    }
});

$streamA->on('close', function ($streamA) {
    $streamA->close();
});

$streamA->write($testString);

$loop->run();

With StreamSelectLoop, I get the results I expect:

Call 1: 4096 bytes - buffer is 4096 bytes
Call 2: 1 bytes - buffer is 4097 bytes

With LibEventLoop:

Call 1: 4096 bytes - buffer is 4096 bytes

And then it hangs.

I have run this test with the same results on Mac OS 10.10.2 with php 5.6.5 and also on Centos 6.5 with 5.5.20.

Recommanded Loop implementation for php7

Hi,

i'm trying to upgrade my app to php7. I used libevent and the matching pecl extension which is not available anymore for php7

What would you recommend ?

Did some of you make the switch already ?
What solution did you choose ?

Thank you for the effort in ReactPHP

Autoloading in `class_exists`

Hi. Just found an issue in the Factory class on master concerning the behavior of class_exists. I'd like to suggest changing class_exists(<classname>) to class_exists(<classname>, FALSE) to prevent autoloading when the class is not defined.

Event::set(): supplied resource is not a valid

There is a heavy script which is running 24x7. Before it worked on php5.6 + libevent + php libevent + react. After update to php 7.1 + libevent + php event (React\EventLoop\ExtEventLoop) + react I got periodical crashes with stack below. I am trying to debug issue, but it is difficult cause issue happens relatively rarely. Any help or ideas would be great.

> [2017-12-11 13:45:47] prod.ALERT: ErrorException: Event::set(): supplied resource is not a valid Socket resource in /home/projects/application/vendor/react/event-loop/src/ExtEventLoop.php:264
> Stack trace:
> #0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(2, 'Event::set(): s...', '/home/projects/...', 264, Array)
> #1 /home/projects/application/vendor/react/event-loop/src/ExtEventLoop.php(264): Event->set(Object(EventBase), Resource id #118542, 20, Object(Closure))
> #2 /home/projects/application/vendor/react/event-loop/src/ExtEventLoop.php(96): React\EventLoop\ExtEventLoop->unsubscribeStreamEvent(Resource id #118542, 2)
> #3 /home/projects/application/vendor/react/stream/src/DuplexResourceStream.php(105): React\EventLoop\ExtEventLoop->removeReadStream(Resource id #118542)
> #4 /home/projects/application/vendor/react/stream/src/DuplexResourceStream.php(139): React\Stream\DuplexResourceStream->pause()
> #5 /home/projects/application/vendor/react/socket/src/Connection.php(116): React\Stream\DuplexResourceStream->close()
> #6 /home/projects/application/vendor/react/http-client/src/Request.php(218): React\Socket\Connection->close()
> #7 /home/projects/application/vendor/react/http-client/src/Request.php(205): React\HttpClient\Request->close()
> #8 /home/projects/application/vendor/react/http-client/src/Request.php(178): React\HttpClient\Request->closeError(Object(RuntimeException))
> #9 /home/projects/application/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(123): React\HttpClient\Request->handleEnd()
> #10 /home/projects/application/vendor/react/stream/src/Util.php(71): Evenement\EventEmitter->emit('end', Array)
> #11 /home/projects/application/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(123): React\Stream\Util::React\Stream\{closure}()
> #12 /home/projects/application/vendor/react/stream/src/DuplexResourceStream.php(196): Evenement\EventEmitter->emit('end')
> #13 [internal function]: React\Stream\DuplexResourceStream->handleData(Resource id #118542)
> #14 /home/projects/application/vendor/react/event-loop/src/ExtEventLoop.php(299): call_user_func(Array, Resource id #118542)
> #15 [internal function]: React\EventLoop\ExtEventLoop->React\EventLoop\{closure}(Resource id #118542, 6, NULL)
> #16 /home/projects/application/vendor/react/event-loop/src/ExtEventLoop.php(182): EventBase->loop(3)
> #17 /home/projects/application/library/Main.php(163): React\EventLoop\ExtEventLoop->run()
> 
> Next Exception: Expected either valid PHP stream or valid PHP socket resource in /home/projects/application/vendor/react/event-loop/src/ExtEventLoop.php:264
> Stack trace:
> #0 /home/projects/application/vendor/react/event-loop/src/ExtEventLoop.php(264): Event->set(Object(EventBase), Resource id #118542, 20, Object(Closure))
> #1 /home/projects/application/vendor/react/event-loop/src/ExtEventLoop.php(96): React\EventLoop\ExtEventLoop->unsubscribeStreamEvent(Resource id #118542, 2)
> #2 /home/projects/application/vendor/react/stream/src/DuplexResourceStream.php(105): React\EventLoop\ExtEventLoop->removeReadStream(Resource id #118542)
> #3 /home/projects/application/vendor/react/stream/src/DuplexResourceStream.php(139): React\Stream\DuplexResourceStream->pause()
> #4 /home/projects/application/vendor/react/socket/src/Connection.php(116): React\Stream\DuplexResourceStream->close()
> #5 /home/projects/application/vendor/react/http-client/src/Request.php(218): React\Socket\Connection->close()
> #6 /home/projects/application/vendor/react/http-client/src/Request.php(205): React\HttpClient\Request->close()
> #7 /home/projects/application/vendor/react/http-client/src/Request.php(178): React\HttpClient\Request->closeError(Object(RuntimeException))
> #8 /home/projects/application/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(123): React\HttpClient\Request->handleEnd()
> #9 /home/projects/application/vendor/react/stream/src/Util.php(71): Evenement\EventEmitter->emit('end', Array)
> #10 /home/projects/application/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(123): React\Stream\Util::React\Stream\{closure}()
> #11 /home/projects/application/vendor/react/stream/src/DuplexResourceStream.php(196): Evenement\EventEmitter->emit('end')
> #12 [internal function]: React\Stream\DuplexResourceStream->handleData(Resource id #118542)
> #13 /home/projects/application/vendor/react/event-loop/src/ExtEventLoop.php(299): call_user_func(Array, Resource id #118542)
> #14 [internal function]: React\EventLoop\ExtEventLoop->React\EventLoop\{closure}(Resource id #118542, 6, NULL)
> #15 /home/projects/application/vendor/react/event-loop/src/ExtEventLoop.php(182): EventBase->loop(3)
> #16 /home/projects/application/library/Main.php(163): React\EventLoop\ExtEventLoop->run()
> 

If tick is called in futureTickQueue we got exception

Hi,

On our project we call futureTick() in case in stream handler we need to wait for new data to populate. It has internal call to tick() that eventually clears current futureTick queue. In FutureTickQueue in tick() we simply call dequeue() exact amount of times equal to queue length at the tick() beginning. The problem is that we don't check if queue is already empty.

Roadmap to stable v1.0.0

Let's face it, this project is stable and has been used in production for years :shipit:

However, we're currently following a v0.X.Y release scheme (http://sentimentalversioning.org/).

We should finally make this explicit and fully adhere to SemVer and release a stable v1.0.0.

To a large extend, a stable v1.0.0 helps making BC breaks more explicit and thus the whole project more reliable from a consumer perspective. This project is actively maintained and has received some major updates in the last weeks and has some major updates planned in the next weeks. Given our current versioning scheme, we'd like to ensure all anticipated BC breaks will be merged before the planned v1.0.0 release.

As such, I've set up a roadmap that enlists only the major changes for each version among with planned release dates towards a stable v1.0.0 release:

v0.4.3 ✅

  • Released 2017-04-27
  • Bugfix release

v0.5.0 ✅

  • Released 2018-04-05
  • Signal handling support
  • Documentation overhaul
  • Reduce public API
  • Throw on error

v1.0.0

  • Planned 2018-Q2?
  • No new changes planned, this should merely mark the previous release as "stable"

This ticket aims to serve as a basic overview and does not contain every single change. Please also see the milestone links and the CHANGELOG for more details.

Obviously, this roadmap is subject to change and I'll try to keep it updated as we progress. In order to avoid cluttering this, please keep discussion in this ticket to a minimum and consider reaching out to us through new tickets or Twitter etc.

Speed up StreamSelectLoop

There is very simple way to speed up StreamSelectLoop, because usleep(0) not skipping sleep, cuz it function call;

$t = microtime(true);
usleep(0);
$r = microtime(true);
echo ($r-$t)*1000000; //69.856643676758

vs

$t = microtime(true);
0 && usleep(0);
$r = microtime(true);
echo ($r-$t)*1000000; //5.9604644775391

So in the cycle with timeout in variable

$timeout = 0;
$start = microtime(true);
for($i = 0; $i < 100000; $i++) {
    usleep($timeout);
}
echo microtime(true) - $t; //6.6996

vs

$timeout = 0;
$start = microtime(true);
for($i = 0; $i < 100000; $i++) {
    $timeout && usleep($timeout); //skip null and 0 sleeps
}
echo microtime(true) - $t; //0.026

Why callbacks cannot throw exceptions?

I'd like to use the event loop to limit the max execution time of a given function, instead of the native set_time_limit. However, the documentation says the callback function should not throw exceptions.

Is there any other way to do this?

$loop->addTimer(0.1, function () {
    throw new TimeoutException('Max execution of 100ms');
});

LibEventLoop doesn't notifies userland code immediately

I'm working on a PHP keylogger using the Linux evdev API (characted devices in /dev/input/).

I'm working on the React interface of the library, which is a specialization of my main class.
Using my main (non-React) class and logging the events, I can get this type of log when I press the space key one time (simplified output) :

-- handleData --   -> handleData called
key=57 value=1     -> keydown on space
-- handleData --
key=57 value=0     -> keyup on space

OK. I pressed space one time and I instantly get two events related to the space key. All good.

Now, using the React extend of my keylogger and doing the same key press :

-- handleData --
key=57 value=1     -> keydown on space

You can notice I don't get the keyup event. Nothing happens until I press another key. So, let's press space another time :

-- handleData --   -> previous log
key=57 value=1     -> previous log
-- handleData --
key=57 value=0     -> it is displayed only now!!
-- handleData --
key=57 value=1     -> ok, expected new keydown
                   -> missing new keyup... 'til I press another key

I was using EventLoop\Factory::create() to get the event loop. It was returning a LibEventLoop. I tried to force the loop class used by replacing the factory with the plain-PHP StreamSelectLoop. And it works perfectly with this loop class.

I can't try with LibEvLoop or ExtEventLoop since these libraries aren't installed on my system.

Maybe it's a quirk of LibEventLoop on character files?
I hope I'm clear enough !

StreamSelectLoop: Timers with very small intervals do not work correctly

Within StreamSelectLoop::run() is the following code:

} elseif ($scheduledAt = $this->timers->getFirst()) { // float
    $timeout = $scheduledAt - $this->timers->getTime(); // float - float
    if ($timeout < 0) {
        $timeout = 0;
    } else {
        $timeout *= self::MICROSECONDS_PER_SECOND; // float * int
    }
}

In the case of a periodic timer with an interval equal to Timer::MIN_INTERVAL (0.000001), the above code, in conjunction with the Timers class, essentially does something like the following:

$currentTime = microtime(true);
$ourTimerInterval = 0.000001;
$nextTimerScheduledAt = $currentTime + $ourTimerInterval;
// $timeout is for stream_select()/usleep() call
$timeout = $nextTimerScheduledAt - $currentTime; // This is NOT equal to 0.000001 due to float error [1]
$timeout *= 1000000; // This looks like it should be (int)1, but it is actually approximately (float)0.95

$timeout is then passed to stream_select() and usleep(), both of which expect int and so cast (float)0.95 to (int)0, not waiting at all when the timer was intended to delay for 1 microsecond. Furthermore, the fix in #37 is bypassed when this issue occurs as (float)0.95 casts to boolean true.

A quick fix would be to apply rounding to $timeout *= self::MICROSECONDS_PER_SECOND;.

[1] https://3v4l.org/FvioX

[Question] How to prevent the amount of ram used from rising in the loop

Hi, I have a problem. I have a loop with a futuretick that connects to the database only once and begins to make requests and update data, the problem is that the percentage of ram on the server does not stop uploading. It goes on and on with each iteration of the loop.

What are the recommendations so that this loop can keep the server running so that this does not happen?
I have to clean the cache?
destroy objects?
or is there something else that makes this happen?

Use monotonic time when available

Currently, PHP doesn't support and built-in way to access the system's monotonic time. That might change in PHP 7.2. I plan to implement a hrtime() function providing access to the high-resolution monotonic system time. If UV is available, but another loop is used, uv_hrtime() could be used in the meantime.

This issue exists to keep track of any improvements in PHP itself and to not forget implementing hrtime() in the future.

https://externals.io/thread/592#email-14248 updated: https://externals.io/message/97502

HHVM test fails because of arbitrary speed not matching.

1) React\Tests\EventLoop\StreamSelectLoopTest::testStopShouldPreventRunFromBlocking
Failed asserting that 0.010394096374512 is less than 0.005.

The purpose of the test is to make sure a timer is not still executed after stop is called.
The timer is set to 1 second, so the test should still work if the speed is adjusted for more HHVM headroom, like 0.05 instead of 0.005.

Optionally inject EventBase into ExtEventLoop

I am working on a project that I think could be complementary to your project:
https://github.com/cameronjacobson/Spas

** Look at examples/* files for a quick glimpse into what I'm trying to do.

Not as a component of React, but by using react as an injectable component in my project. Similar to how "Request" variables are injected into callbacks in Silex. I would write a ControllerResolver that injected additional components. The reason I'm writing this note is because my project assumes its own EventBase (using EventHttp) is already instantiated. And since using React as an injectable component would be optional, it wouldn't necessarily make sense to do all the React initialization up front. So if a user could inject a React event-loop (using the EventBase already instantiated) the user could use React inside the Silex controller seamlessly.

When reviewing the event-loop project I noted the 'private' visibility for the EventBase. I understand that my use-case may not be something you have thought of, but I think it's a valid one and I think would be pretty powerful way to utilize React.

I see that another option is for me to just implement the LoopInterface in my own implementation of an EventLoop for your project, and perhaps you feel better going that route, but given the new use case it seems it could open alot of possibilities for your project if either visibility was increased / getters / setters, and / or perhaps EventBase was injectable into the event-loop itself.

Possibility to resume the loop

Hi,

You can read my original post here. I described issue with using block-react lib since there is no way to resume the stopped loop. @clue advised to use second loop (which I use now and it's only non-perfect, working solution), but as i read in issues and PRs here, You're aiming to make one global loop, so this won't work anymore. My idea is to make possible to resume React loop and method implementing this should only set running to true (exactly opposite what stop method does). This shouldn't break anything, just adds new possibility :)

I also understand what @clue mentioned that we shouldn't mix async and sync code, but we're not living in perfect world ;)

Any thoughts appreciated.

Add timer within launched loop doesn't work

Hey,

I'm making face to a problem, i need to dynamcally attach timer. I'm on the context of websocket server (on top of ratchet) and i would use timer to emit message.

So i have created a component to attach timer on specific connection. But the callback is just played once :(

It's the expected behavior ? Am i on the wrong to achieve that ?

Thanks

Suggest values in composer.json

in composer.json the suggest attributes have version "constraints".

According to the composer documentation:
"The format is like package links above, except that the values are free text and not version constraints."
Generally it's saying that it will not fail when a wrong version is install.

Proposed solutions:

  1. Maybe it's more useful to add a useful description so people know which extension is best to install. The version constraints can still be included in that description.
  2. Maybe it's useful to write separate "driver" packages with the extensions as requirements. And make use of the provide to implement a virtual packages, which is "suggested" or "required" in this package.

The latter is of course the more demanding proposal.

Multiple event loop

How can I have multiple event loop in a script??Without blocking each other . I want to use select and event

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.