reactphp / reactphp Goto Github PK
View Code? Open in Web Editor NEWEvent-driven, non-blocking I/O with PHP.
Home Page: https://reactphp.org
License: MIT License
Event-driven, non-blocking I/O with PHP.
Home Page: https://reactphp.org
License: MIT License
We should have an async DNS client. Consider this a challenge.
Could be used as a basis: http://d.hatena.ne.jp/moriyoshi/20070204/1170599839
You cannot poll file streams with epoll. Libevent does not handle this gracefully and throws awful errors in your face.
We should detect the epoll backend in the libevent event loop and instead of adding file streams to the event loop, add them to a separate array and consider it always ready.
We might be able to find out if a stream is a file stream by using stream_get_meta_data
. I really hope a PHP stream cannot change from memory to file dynamically. If that is the case, we're kind of screwed with libevent.
Streal from node: http://nodejs.org/api/net.html
This allows throttling and prevents buffering all incoming data in memory if we cannot deliver it fast enough.
We should definitely look into the stream API: http://nodejs.org/api/stream.html
When the client requests an upgrade, that should be handled separately.
Thinking at a high level here, I'd like to propose ConnectionInterface
methods be renamed to from write
to send
or deliver
and end
to disconnect
.
write
means write some data to a stream. Now that we have buffering and async I/O send
makes more sense. We're not writing bytes to a buffer, we've abstracted that, the user is sending a message. It makes more sense the higher up we go in the chain. Request::send
, from the users perspective, is sending a whole message where the abstraction is writing bytes when the buffer is available.
I find end
unclear. A Connection
is a proxy representation of a connected client/user. Would documentation read "Call end() to end the connection to the user"? I find disconnect
to be much more succinct.
With generic interfaces for async caching.
There is an issue with doing non-blocking HTTP requests with stream functions: fopen actually returns only after the server has sent the response headers, which can cause the script to block for some times.
It would be awesome if react-php allowed to do fully-asynchronous HTTP requests.
Sometimes apps will need synchronous I/O. This should not take place in the event loop, as it would block everything. Instead, it should be distributed to workers.
React should provide some way to interface with these workers (workers should use pre-forking). This could be a simple message queue abstraction interface or possibly a full-blown component that provides integration with redis, zeromq, maybe even rabbitmq (if somebody makes a non-blocking client lib).
Line 20 of the file React\Socket\Server.php
raises a PHP warning if the PHP function stream_socket_server()
is unable to connect to the specified host and port, e.g.
stream_socket_server(): unable to connect to tcp://0.0.0.0:80
The warning should be supressed via @
, so the fixed section would look like as follows:
<?php
///...
$this->master = @stream_socket_server("tcp://$host:$port", $errno, $errstr);
// if (false ...
Right now there doesn't seem to be a simple way to automatically gzip responses and attach the appropriate content-encoding header. Right now you have to do something like this:
$app->get('/', function(React\Http\Request $request, React\Http\Response $response) use (&$i) {
$text = gzencode("A generic response with gzip.\n");
$headers = array('Content-Encoding' => 'gzip',
'Content-Type' => 'text/plain',
'Content-Length' => strlen($text));
$response->writeHead(200, $headers);
$response->end($text);
});
Which works but this gets tedious and I believe its a common enough (and expected) feature that even forcing people to implement an abstraction themselves isn't the best path.
Problem when using composer to install react on ubuntu 12.04.
My composer.json file is:
{
"require": {
"react/react": "dev-master"
}
}
Terminal output:
$ composer install
Installing dependencies
Your requirements could not be solved to an installable set of packages.
Problems:
- Problem caused by:
- Package "react/react-9999999-dev" contains the rule react/react requires evenement/evenement (== 9999999-dev). Any of these packages satisfy the dependency: evenement/evenement-9999999-dev.
- Installation request for react/react == 9999999-dev: Satisfiable by [react/react-dev-master].
- Package "guzzle/guzzle-2.5.0.0" contains the rule guzzle/guzzle requires ext-curl ([]). No package satisfies this dependency.
about ev : http://pecl.php.net/package/ev
It might be possible to do some sort of co-operative multitasking by using generators, which could potentially replace promises in the future.
Note: It has been done in python as well.
I'm writing a small application using React and Ratchet that opens up a few long-running external processes, and redirects some of their output (via stdout) through a websocket connection.
Using popen
and React's stream
class to talk to the external process usually works just fine, and the process's output gets sent to the websocket as it executes -- as one would expect. Some processes, however, block the event loop until they've completed running.
Inside my Ratchet application, I can run
$ping = new Stream(popen("ping -t 127.0.0.1",'r'),$server->loop);
$ping->on('data',function($data) use ($from){
$from->send($data);
});
and ping will continuously direct its output through my websocket connection, $from
.
However, if I use a different executable (in this case, the Adobe F4V Post-Processor), I get no output from f4vpp, or anything else in my event loop (say, the ping
command above) until f4vpp exits.
$f4vpp = new Stream(popen("f4vpp -v -i in.f4v -o out.mp4",'r'),$server->loop);
$f4vpp->on('data',function($data) use ($from){
$from->send($data);
});
What's going on here? Is this user error, or a legitimate shortcoming in React or PHP on win32?
Implement a true non-blocking MySQL driver in pure PHP.
Port the mongrel http parser to PHP. Or maybe the node one.
Also provide adapters for PHP extensions:
According to the comments on the libevent PHP manual page, libevent supports timed events through the undocumented event_timer_new function.
For StreamSelectLoop we could re-implement it by checking the time within tick
.
@nrk is working on this.
Here is the code I was using against the master branch: https://gist.github.com/2653190
If I call $conn->end()
the client receives the write buffer (HTTP Response) but the connection does not close. If I call $conn->close()
the server does close the connection, but does not receive the write buffer.
The write buffer is currently in the Socket component. But it really is more general purpose. For libevent we can provide an implementation that uses event_buffer_write, which may give us some speed improvements.
Using a github service hook.
PHP 5.4.0 was released on 01-Mar-2012. The end of life for PHP 5.3.x is in March 2013.
The major decision factor is a) ease of getting started; b) ease of deployment.
Getting started
In case users do not have PHP 5.4.x on their local machines, we must provide install instructions. For example, OSX ships with 5.3, so we should point users to either php-osx or homebrew-php.
This seems like an acceptable requirement to me.
Deployment
It is critical that major distros ship with PHP 5.4 before we bump the requirement.
Proposal
IMO we should wait at least until debian wheezy is out. Which would mean bumping whenever that happens, hopefully within the next 2-3 months.
Feedback please.
It allows to detect TCP network errors and the likes. A slightly more accurate description can be found here.
Thanks to @DaveRandom.
Considering this script :
<?php
include 'vendor/autoload.php';
use React\Dns\Resolver\Factory as DnsResolverFactory;
use React\HttpClient\ConnectionManager;
use React\HttpClient\SecureConnectionManager;
use React\HttpClient\Client;
use React\EventLoop\Factory as LoopFactory;
use React\HttpClient\Response;
$loop = LoopFactory::create();
$dnsResolverFactory = new DnsResolverFactory();
$dnsResolver = $dnsResolverFactory->createCached('8.8.8.8', $loop);
$connectionManager = new ConnectionManager($loop, $dnsResolver);
$secureConnectionManager = new SecureConnectionManager($loop, $dnsResolver);
$client = new Client($loop, $connectionManager, $secureConnectionManager);
$reference = memory_get_usage();
$loop->addPeriodicTimer(1, function () use ($client, &$reference) {
$request = $client->request('GET', 'http://127.0.0.1:80/');
$request->writeHead();
$memory = memory_get_usage();
echo sprintf("memory usage : %d, delta : %d\n", $memory, $memory - $reference);
$reference = $memory;
});
$loop->run();
and the output :
memory usage : 1625544, delta : 906936
memory usage : 1834208, delta : 208664
memory usage : 1852904, delta : 18696
memory usage : 1871600, delta : 18696
memory usage : 1890296, delta : 18696
memory usage : 1908992, delta : 18696
memory usage : 1927688, delta : 18696
memory usage : 1946384, delta : 18696
memory usage : 1965080, delta : 18696
memory usage : 1983776, delta : 18696
memory usage : 2002472, delta : 18696
memory usage : 2021168, delta : 18696
memory usage : 2039864, delta : 18696
memory usage : 2058560, delta : 18696
memory usage : 2077256, delta : 18696
It seems a leak happens.
This happens with both StreamSelectLop
and LibEventLoop
. The leak stops if $request->writeHead();
is commented
See also https://github.com/m4rw3r/php-libev
Reproduce script:
<?php
// script to test for mem leaks
// You can test it using:
// siege localhost:8080
require __DIR__.'/../vendor/autoload.php';
$loop = new React\EventLoop\LibEventLoop();
$socket = new React\Socket\Server($loop);
$http = new React\Http\Server($socket, $loop);
$i = 0;
$http->on('request', function ($request, $response) use ($loop, &$i) {
$i++;
$response->writeHead();
$response->end("Hello World!\n");
$loop->addTimer(1, function () {
// noop
});
});
$loop->addPeriodicTimer(2, function () use (&$i) {
$kmem = memory_get_usage(true) / 1024;
echo "Request: $i\n";
echo "Memory: $kmem KiB\n";
});
$socket->listen(8080);
$loop->run();
$ siege -c 50 localhost:8080
Memory keeps increasing, something is not being cleaned up properly.
We could implement the spdy protocol, possibly by porting the igrigorik/spdy ruby gem. This would be a "Spdy" component that integrates with the Http one.
If you remove the testAddPeriodicTimerCancelsItself
method from React\Tests\EventLoop\Timer\LibEventTimerTest
you will notice the following error:
PHP Fatal error: Cannot destroy active lambda function in /Users/igor/code/react/src/React/EventLoop/LibEventLoop.php on line 179
Ping @cameronjacobson.
A very nice to have would be a Vagrant setup for React. Someone looking to poke around with React but not ready to install libs on their system. Recipes would include:
Not sure if this would be in /vagrant of React repo or a separate sandbox repo - open to suggestions.
Edit: Links fixed
Edit2: Removed dual PHP installation
We should port the promises portion of a promises library to PHP to have a nicer way of dealing with callbacks.
JS implementations:
By using the unix://
stream wrapper with socket_server it should already be possible, but we need to expose this functionality somehow.
Provides eventloop, buffer, dns, (socket?) and http implementations.
Kinda depends on #42.
Espresso in its current form is only a proof of concept. As such, I think we should drop it from the core project and move it to a third party dependency.
This will allow similar third party frameworks to arise without putting too much weight on the unstable espresso component itself.
Poke @cboden.
By re-using the same parser instance we can save on amount of objects created. This is also the way ratchet handles http parsing.
does the minimum php version need to be bumped up because of evenement?
Some todos:
We also need to decide how to handle encoding of outgoing data. There are different use cases for modifying the response, some of which may require buffering: websockets, gzip compression, chunked encoding.
I encountered symptoms of a memory leak while writing some simple middleware for a 3rd party socket-based application. The solution can be found in the following gist.
Note the calls to gc_enable() and gc_collect_cycles().
EDIT: technically not a memory leak, but named as such to hopefully get the attention of folks thinking this is what they're experiencing.
Possible by by using a stream context, see comment in: http://php.net/stream_socket_server
Needs coordination with ratchet, since we have common guzzle deps.
This ticket needs to wait for status of #131.
The http-client example no longer works as of commit 8d5f660 - this is where Promise was added to DNS.
sorry, libevent extensions's problem.
This is mainly for the subtree splits.
Including:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.