Comments (17)
Need to translate this into documentation, but write my thoughts and the outlines of our current plan down at: https://blog.wyrihaximus.net/2021/12/async-and-await-at-the-edge-with-reactphp/
from async.
A valid reason I can think of to call await
in the main fiber is to determine the exit code of the application. Note that the order of things added to the event loop is important as described in @WyriHaximus's blog.
<?php
use React\EventLoop\Loop;
use function React\Async\async;
use function React\Async\await;
require_once __DIR__ . '/vendor/autoload.php';
$timer = Loop::addPeriodicTimer(1, fn() => print 'tick' . PHP_EOL);
$exit = await(async(function () use ($timer) {
Loop::addTimer(10, fn() => Loop::cancelTimer($timer));
return 1;
}));
exit($exit);
from async.
@bartvanhoutte yes, each async will create a new fiber.
from async.
This code causes Segmentation fault
error (CLI on Windows):
<?php
require 'vendor/autoload.php';
$browser = new \React\Http\Browser();
/** @var \Psr\Http\Message\ResponseInterface $response */
$response = \React\Async\await($browser->get('https://github.com'));
var_dump((string)$response->getBody());
...but only for "github.com", for "google.com" returns proper result.
This works fine in both cases:
<?php
require 'vendor/autoload.php';
$browser = new \React\Http\Browser();
$browser
->get('https://github.com')
->then(fn (\Psr\Http\Message\ResponseInterface $response) => var_dump((string)$response->getBody()));
EDIT:
Problem exists only on Windows PHP compilation - on linux all works correctly.
EDIT2:
Please check it for yourself on your environment, on my it's not predictable. Yesterday it worked, now it doesn't - in CLI I have segmentation fault.
from async.
@szado Thank you for reporting, this definitely shouldn't have happened!
I've tried reproducing this a number of times, but can not reproduce the problem you're seeing on Linux.
A segmentation fault is not something that userland PHP code should be able to trigger. There is also no platform-specific code in ReactPHP involved, so I can only suspect this is an issue with the fibers implementation in PHP itself. I don't think this boils down to an issue in ReactPHP itself, so I wonder if we can break this down to a reproducible script that also shows this segmentation fault without ReactPHP?
Accordingly, it looks like this should probably be reported upstream in PHP. Can anybody take a look at this and link/report back here?
Thank you!
from async.
@clue maybe this code will be helpful: https://github.com/szado/reactphp-connection-pool/blob/master/test.php
It triggers Segmentation fault
and Error: Value of type null is not callable in ...\reactphp-connection-pool\vendor\react\async\src\SimpleFiber.php on line 59
(it can be more directly related to ReactPHP) on Windows and Linux.
from async.
Tested on both Windows and Linux, I didn't notice any difference. The error is present both there and there.
Here is my piece of code. I'm trying to wait for a WebSocket response and give it back. As a result, I get an error. If you don't wait for an answer, but just give out any value, everything goes well
return new Promise(function (callable $resolve) {
ReplyRoute::reply('Server:GetValue', function (int $value) use ($resolve) {
$resolve($value); // Error
});
$resolve(100); // Good
});
from async.
@szado I can reproduce that error and looking into the exact cause (probably related to PHP Fatal error: Uncaught TypeError: Szado\React\ConnectionPool\ConnectionPool::retryWithDelay(): Return value must be of type Szado\React\ConnectionPool\ConnectionAdapters\ConnectionAdapterInterface, null returned
) and then work on a fix.
The browser segfault I can't reproduce on windows. But might be the same root cause internally.
from async.
Ran into the same error.
<?php
use React\Promise\Promise;
use React\Promise\PromiseInterface;
use function React\Async\await;
use function React\Promise\resolve;
require_once __DIR__ . '/vendor/autoload.php';
function test(): PromiseInterface {
$resolver = function ($resolve, $reject) {
await(resolve());
$resolve();
};
return new Promise($resolver);
}
await(test());
[docker://fiber:latest/]:php /opt/project/index.php
Fatal error: Uncaught Error: Value of type null is not callable in /opt/project/vendor/react/async/src/SimpleFiber.php on line 59
Error: Value of type null is not callable in /opt/project/vendor/react/async/src/SimpleFiber.php on line 59
Call Stack:
0.0002 391640 1. {main}() /opt/project/index.php:0
0.0886 4169192 2. React\Async\await($promise = class React\Promise\Promise { private $canceller = NULL; private $result = NULL; private $handlers = [0 => class Closure { virtual $closure = "React\Promise\Promise::React\Promise\{closure}", ... }]; private $progressHandlers = [0 => class Closure { virtual $closure = "React\Promise\Promise::React\Promise\{closure}", ... }]; private $requiredCancelRequests = 0; private $cancelRequests = 0 }) /opt/project/index.php:19
0.0886 4174816 3. React\Async\SimpleFiber->suspend() /opt/project/vendor/react/async/src/functions.php:89
from async.
TL;DR You're only having one fiber (the main fiber) running and you want to await for a promise twice, it's simply not possible.
from async.
P.S. Will get you a longer response somewhere between tonight and the end of the weekend. Working on a bunch of examples and a blog post on this.
from async.
@WyriHaximus 👌 It might lead to some unexpected errors when you're using a 3rd party library. Right now the example is pretty useless but replace await(resolve())
with some 3rd party function that undirectly calls await
somewhere and you're stuck. Will try to find a workaround in my case.
from async.
Something like this instead?
<?php
use React\Promise\PromiseInterface;
use function React\Async\async;
use function React\Async\await;
use function React\Promise\resolve;
require_once __DIR__ . '/vendor/autoload.php';
function test(): PromiseInterface {
return async(function () {
await(resolve());
});
}
await(test());
from async.
Just filed #18 that helps with a few cases mentioned in this issue. And intentionally all of them (except the segfault), but I'd have to test that
from async.
I can no longer reproduce the error from #16 (comment), however there seems to be an issue with timers using async
.
<?php
use React\EventLoop\Loop;
use function React\Async\async;
use function React\Async\await;
require_once __DIR__ . '/vendor/autoload.php';
function foo()
{
print __FUNCTION__ . PHP_EOL;
await(async(fn() => null));
}
Loop::addTimer(5, fn() => foo());
[docker://fiber:latest/]:php /opt/project/index.php
foo
foo
Fatal error: Uncaught Error: Value of type null is not callable in /opt/project/vendor/react/async/src/SimpleFiber.php on line 59
The timer is executed twice causing the error.
Upon further inspection, it looks like the timer is never removed from the list of timers in \React\EventLoop\Timer\Timers
.
from async.
The same error occurs when an EventLoop is created manually without using \React\EventLoop\Loop::get
SimpleFiber
itself creates a new loop in Loop::run()
, resulting in two loops.
https://github.com/reactphp/async/blob/main/src/SimpleFiber.php#L44
Example:
<?php
$loop = new \React\EventLoop\ExtEventLoop();
//\React\EventLoop\Loop::set($loop); // solution
$deferred = new \React\Promise\Deferred();
$loop->futureTick(static fn() => $deferred->resolve());
\React\Async\await($deferred->promise());
$loop->run();
Result: Error: Value of type null is not callable in /vendor/react/async/src/SimpleFiber.php:53
After uncommenting Loop::set
the problem is solved.
But \React\EventLoop\Loop::set
is marked as @internal
, so this solution is not safe.
from async.
@bartvanhoutte Very good input, I can see where you're coming from! It looks like most of the issues discussed in this ticket stem from lack of documentation how to use the async()
and await()
functions, so I've just filed #26 to add appropriate documentation. The gist is that making your example work is as simple as updating it like this (refs #19):
<?php
use React\EventLoop\Loop;
use function React\Async\async;
use function React\Async\await;
require_once __DIR__ . '/vendor/autoload.php';
function foo()
{
print __FUNCTION__ . PHP_EOL;
- await(async(fn() => null));
+ await(async(fn() => null)()); // or omit as this is a NO-OP
}
- Loop::addTimer(5, fn() => foo());
+ Loop::addTimer(5, async(fn() => foo())); // or Loop::addTimer(5, async('foo'));
@Provoker Interesting find! The await()
function indeed assumes it's executing the default loop, so you should simply remove any references to an explicit loop instance. See also https://github.com/reactphp/event-loop#loop
from async.
Related Issues (14)
- Fibers + Cancellation HOT 2
- Use 0.x versions HOT 5
- Error: event_base_loop reentrant invocation HOT 9
- await() doesn't work with streaming HTTP response body HOT 9
- Allow `iterable` instead of `array` for `parallel()`, `series()` and `waterfall()` HOT 1
- Cancellation semantics for `async()` and `coroutine()` HOT 2
- Support Promise v3 HOT 1
- Using await in a destructor HOT 7
- Improve error reporting when incorrectly using `await()` (Value of type null is not callable in src/SimpleFiber.php:66) HOT 6
- Struggling with the simplest example HOT 1
- Basic question 'bout reactphp HOT 9
- reactphp/async
- \React\Async\async did not invokes in on('data') event HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from async.