guzzle / promises Goto Github PK
View Code? Open in Web Editor NEWPromises/A+ library for PHP with synchronous support
License: MIT License
Promises/A+ library for PHP with synchronous support
License: MIT License
I've noticed (#73) that uncaught errors do not throw exceptions, this can make debugging really difficult because there isn't an obvious reason of why a promise chain is breaking.
I believe in JavaScript, an uncaught promise error throws a fatal error, so I think throwing an exception (outside of the promise chain) for uncaught promises would be a good idea here.
Hello,
I'm implementing a DB client for a database using HTTP
as its wire protocol. I'm trying to implement a wrapper for the promises returned by the Guzzle\Client
, but it's clear that I've misunderstood something about this library ^_^ .
Before starting delving into details, my problem seems to be simple: In theory my code is pretending to "catch" Guzzle's exceptions and wrapping it with my own class. What is happening is the Guzzle exception is thrown at some point which I can't identify, and remains uncaught.
Here you can see my code, full of debug prints:
<?php
namespace Druid4PHP\Responses;
use Druid4PHP\Errors\DruidRequestError;
use Druid4PHP\Errors\DruidServerError;
use Druid4PHP\Errors\DruidResponseParseError;
use Druid4PHP\Queries\Query;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\ResponseInterface;
/**
* @method Response|array wait($unwrap = true)
*/
final class AsyncResponse extends Promise
{
/** @var Query */
private $query;
/** @var PromiseInterface */
private $httpPromise;
/** @var bool */
private $encapsulation;
/**
* AsyncResponse constructor.
* @param Query $query
* @param PromiseInterface $httpPromise
* @param bool $encapsulation
*/
public function __construct(Query $query, PromiseInterface $httpPromise, $encapsulation = true)
{
echo "\nINSIDE __construct\n";
$this->query = $query;
$this->httpPromise = $httpPromise->then(
function (ResponseInterface $response) {
echo "\nIN A FEW nanos WE'LL GET INTO this->onFulfilledHttpPromise\n";
return $this->onFulfilledHttpPromise($response);
},
function (\Exception $e) {
echo "\nIN A FEW nanos WE'LL GET INTO this->onRejectedHttpPromise\n";
return $this->onRejectedHttpPromise($e);
}
);
$this->encapsulation = $encapsulation;
parent::__construct(
function () {
echo "\nIN A FEW nanos WE'LL GET INTO this->waitHandler\n";
return $this->waitHandler();
},
function () {
echo "\nIN A FEW nanos WE'LL GET INTO this->cancelHandler\n";
return $this->cancelHandler();
}
);
echo "\nGOING OUT OF __construct\n";
}
private function waitHandler()
{
echo "\nNOW WE'LL CALL httpPromise->wait\n";
$this->httpPromise->wait();
echo "\nNOW WE'VE CALLED httpPromise->wait\n\n";
}
private function cancelHandler()
{
echo "\nNOW WE'LL CALL httpPromise->cancel\n";
$this->httpPromise->cancel();
echo "\nNOW WE'VE CALLED httpPromise->cancel\n";
}
private function onFulfilledHttpPromise(ResponseInterface $response)
{
echo "\nINSIDE onFulfilledHttpPromise\n";
// TODO: allow stream decoding without having to call getContents.
$rawResponse = $response->getBody()->getContents();
$rawResults = json_decode($rawResponse, true);
if (JSON_ERROR_NONE !== json_last_error()) {
throw new DruidResponseParseError($this->query, $rawResponse, 'Received invalid JSON');
}
echo "\nIN A FEW nanos WE'll GO INSIDE this->resolve\n";
$this->resolve(
$this->encapsulation ? $this->query->parseResponse($rawResults) : $rawResults
);
echo "\nGOING OUT OF onFulfilledHttpPromise\n";
}
private function onRejectedHttpPromise(\Exception $e)
{
echo "\nINSIDE onRejectedHttpPromise (".get_class($this).")\n";
$eCode = $e->getCode();
if ($eCode >= 500 && $eCode < 600) {
$this->reject(new DruidServerError($this->query, $e));
} else {
$this->reject(new DruidRequestError($this->query, $e));
}
echo "\nGOING OUT OF onRejectedHttpPromise\n";
}
}
and here you can see the output of one of my executions:
Starting with timeseries queries:
INSIDE __construct
GOING OUT OF __construct
IN A FEW nanos WE'LL GET INTO this->waitHandler
NOW WE'LL CALL httpPromise->wait
IN A FEW nanos WE'LL GET INTO this->onRejectedHttpPromise
INSIDE onRejectedHttpPromise (Druid4PHP\Responses\AsyncResponse)
GOING OUT OF onRejectedHttpPromise
NOW WE'VE CALLED httpPromise->wait
PHP Fatal error: Uncaught exception 'GuzzleHttp\Exception\ServerException' with message 'Server error: `POST http://127.0.0.1:8082/druid/v2/` resulted in a `500 Internal Server Error` response:
{"error":"Instantiation of [simple type, class io.druid.query.timeseries.TimeseriesQuery] value failed: Missing fields [ (truncated...)
' in /home/acorrea/PhpstormProjects/Druid4PHP/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:107
Stack trace:
#0 /home/acorrea/PhpstormProjects/Druid4PHP/vendor/guzzlehttp/guzzle/src/Middleware.php(65): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response))
#1 /home/acorrea/PhpstormProjects/Druid4PHP/vendor/guzzlehttp/promises/src/Promise.php(201): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Response))
#2 /home/acorrea/PhpstormProjects/Druid4PHP/vendor/guzzlehttp/promises/src/Promise.php(154): GuzzleHttp\Promise\Promise::callHandler(1, Object(GuzzleHttp\Psr7\Response), Array)
#3 /home/acorrea/PhpstormProjects/ in /home/acorrea/PhpstormProjects/Druid4PHP/src/Responses/AsyncResponse.php on line 116
what is surprising to me is the exception is being thrown after this piece if code ( $this->httpPromise->wait();
) gets executed, and not during its execution.
Any idea to fix my implementation?
Thank you in advance.
See reactphp/promise#66 please
I need guzzlehttp/promises
implements done()
https://github.com/reactphp/promise#done-vs-then
Running this example code you wrote in a REPL (with php -a
) will never output the value
string:
use GuzzleHttp\Promise\FulfilledPromise;
$promise = new FulfilledPromise('value');
// Fulfilled callbacks are immediately invoked.
$promise->then(function ($value) {
echo $value;
});
I tried to write some data in a file instead of writing on the standard output, but the issue is the same: the $onFulfilled
and $onRejected
functions are never called while it works perfectly in a dedicated PHP file.
This issue also occurs with Psy Shell.
How can I convert guzzle/promises to reactphp/promise ?
// $guzzlePromise is an instance of GuzzleHttp\Promise\Promise and is a result of third party library
$reactPromise = convert($guzzlePromise);
This is not an issue, I just wanted to get your opinion on a topic.
To resolve a promise we do
$promise->then(function[...]
The callback parameter gets the ResponseInterface $response
as function parameter. What if I don't want to use that value? If I just want to log something, or dunno, do something else which has nothing to do with the response. Do you think it's good practice to do $promise->then(function ()
or would you always write $promise->then(function (ResponseInterface $response))
even though you won't need that parameter?
Was just wondering, because omitting the parameter would mean, that we are getting a warning about calling a method with no parameter, right?
If we're brainstorming on 2.0 ideas... then what about removing the concept of a global dependency on a TaskQueue? In the current implementation, promises are added to a global TaskQueue. That queue can also be swapped out for other queues if needed (like React), but doing so might have implications on other aspects of an application that were relying on a different global TaskQueue's behavior. The bigger problem is that because there's a global TaskQueue, Guzzle can't be used in multiple threads.
A better approach would be to require that a promise is created with a reference to the TaskQueue so that chaining off of a promise would add the tasks to the right queue.
This kind of change would probably require another abstraction and a lot of work to ensure it is ergonomic. I'd also be interested to see if we could ensure that there is not a circular reference between a promise and a TaskQueue.
Hi.
I'm thinking about different ways to use Promise objects and I just noticed I wouldn't be able to extend the Promise object without rewriting some code.
Maybe using static::class instead of the literal class name in https://github.com/guzzle/promises/blob/master/src/Promise.php#L35 is all that would be needed.
It's not a real issue right now, just sharing this idea.
Cheers.
I am switching to Guzzle Promise from React Promise. But I don't know how to do it in Guzzle if I want to wait all promised to be resolved.
I was building some async code that triggers a delayed retry in the case of an error, similar to:
$promise = $client->getAsync(...);
$promise->then(
function ($result) { ... },
function ($error) {
sleep(5);
$client->getAsync(...);
}
);
Of course, sleep(5)
is blocking. Is there an asynchronous equivalent for sleep, such as a promise that will resolve within a wait()
call after the given amount of time? If not, can one be added to the library?
I think it's good that we have a method like set_exception_handler
for promise that sets a user-defined unhandled promise rejection handler function
In README.md in a few examples the method deliver is used. This method is not available anymore. Maybe the examples should use resolve now? I saw that deliver was a private method in early commits. (Would the examples work with a private method?)
I have a problem with my Bearer-Authorization in Guzzle-HTTP. I use it to test my PHP-REST-API with PHPUnit.
Here is my test method:
public
function testGetMe()
{
$client = new Client([
'base_uri' => $this->apiBaseURL
]);
$data = ['email' => $email, 'password' => '12345'];
$client->post('register', [
'form_params' => $data]
);
$responseJson = json_decode($response->getBody());
$myToken = $responseJson->data->token;
$response = $client->request('GET', 'users', [
'headers' => [
'Authorization' => 'Bearer '.$myToken
],
'debug' => true
]);
}
`
But if I set the token hard coded like this:
`
public function testGetMe()
{
$client = new Client([
'base_uri' => $this->apiBaseURL
]);
$data = ['email' => $email, 'password' => '12345'];
$client->post('register', [
'form_params' => $data]
);
$responseJson = json_decode($response->getBody());
$myToken = eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE0NjQ5NzExMzQsImp0aSI6IjByR3FpOW15Rm1rRGo2TU9sMVhkK3dRU3p1V0pWejM1UEhiU2dTMmg5SEU9IiwiaXNzIjoiQXBwTmFtZSIsIm5iZiI6MTQ2NDk3MTE0NCwiZXhwIjoxNDY0OTczMTQ0LCJzdWIiOiJ0ZXN0QG1haWwuZGUifQ.yA4a_S6ILCeqENm00H712g9uF5g9eSz_BmnaMDdZ2r4p5e1q88g0T09IG2WKCi1oExoBfQ8VTmKeX6ZQv0RydQ;
$response = $client->request('GET', 'users', [
'headers' => [
'Authorization' => 'Bearer '.$myToken
],
'debug' => true
]);
}
`
and also with Postman, it is working. It's the same token which I receive from my REST-API.
When I debug the code & wait on line: $response = $client->request('GET', 'users'... the test is ok... seems to be something wrong with asynch requesting ?
Do you have any ideas what's wrong?
Please tag a release.
I would expect the 3 ->then
to come up in the 3rd place. Is this a bug or as per design? What is the logic behind it?
It looks like a bug because of chaining ->then()->then
, since on the fair race, one then comes after the other but always on the promise object instead of in the return value of the last then...
$cheating = new GuzzleHttp\Promise\Promise(
function () use(&$cheating){
$cheating->resolve(null);
echo "\n--- Finish line ---\n";
}
);
$cheating->then(function() {
echo "I'm the #1!\n";
})->then(function() {
echo "I'm the #2...\n";
});
$cheating->then(function() {
echo "Haha! And I'm the #3? Nop!\n";
});
$cheating->wait(false);
$fairRace = new GuzzleHttp\Promise\Promise(
function () use(&$fairRace){
$fairRace->resolve(null);
echo "\n--- Finish line on Fair Race ---\n";
}
);
$fairRace->then(function() {
echo "I'm the #1!\n";
});
$fairRace->then(function() {
echo "I'm the #2...\n";
});
$fairRace->then(function() {
echo "I'm the #3 :(\n";
});
$fairRace->wait(false);
This is the output I see:
--- Finish line ---
I'm the #1!
Haha! And I'm the #3? Nop!
I'm the #2...
--- Finish line on Fair Race ---
I'm the #1!
I'm the #2...
I'm the #3 :(
My composer.lock says I'm using 1.2
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "c10d860e2a9595f8883527fa0021c7da9e65f579"
$p = new Promise();
$p->then(function () {
$inner = new Promise();
$inner->then(function () {
throw new \RuntimeException('This exception should not be trapped');
});
$inner->resolve(true);
$inner->wait();
print_r(['state' => $inner->getState()]);
return $inner;
});
$p->resolve(true);
$p->wait();
print_r(['state' => $inner->getState()]);
In this scenario, the RuntimeException
should not be trapped. Both promises are correctly fulfilled but the exception is never seen.
RuntimeException
is thrown.RuntimeException
is never seen.here's my example:
// Build Asynchronous Promise
$promise = $this->client->requestAsync($this->method, $path, $options);
// Extract target data from response JSON after request fulfilled
$promise->then(
function ($response) {
$result = GuzzleResponseParser::parse($response);
$extracted = $this->getTargetDataFromResult($result);
//This dumps the right data
//var_dump($extracted);
//exit();
// This, however, does not work as I'd expect. It doesn't error, but see notes below.
return $extracted;
}
);
I am later using
$results = Promise\unwrap($promises);
foreach ($results as $key => $result) {
$this->data[$key] = $result;
}
I was hoping the $extracted
in the then()
closure would translate to the $result
in the post-unwrap loop, but this does not happen. I see the regular result, not the extracted result.
Am I going about this wrong? I've reviewed documentation and can't seem to find what I need. Might the be another way to do this, or is it not possible? Thanks in advance!
As per #58 (comment)
Hi
From the guide in the readme:
use GuzzleHttp\Promise\Promise;
$promise = new Promise();
$promise
->then(function ($value) {
// Return a value and don't break the chain
return "Hello, " . $value;
})
// This then is executed after the first then and receives the value
// returned from the first then.
->then(function ($value) {
echo $value;
});
// Resolving the promise triggers the $onFulfilled callbacks and outputs
// "Hello, reader".
$promise->resolve('reader.');
Should output "Hello, reader".
However, this doesn't happen until it appears a shutdown handler is called: https://github.com/guzzle/promises/blob/master/src/TaskQueue.php#L21 or the waitIfPending()
method is called.
If a promise is resolved manually, then the callbacks DO NOT fire. I can't seem to work out if this is intentional or a bug, it doesn't make sense that the handlers are called only in one scenario of waiting for a promise.
Can someone explain.
Thanks
https://github.com/guzzle/promises/blob/master/src/Promise.php#L35
$p = new static(null, [$this, 'cancel']);
wish u improve it
I have a list of promises where I want to get the results of those that managed to succeed even when one or more fails. Can I do this with all
?
Provide some good example working one...
Hello,
there is an error in the documentation. The last piece of shown code refers to the deliver
method, but this method does not exist in the whole Promises code base:
$promise = new Promise();
$promise->then(function ($value) { echo $value; });
// The promise is the deferred value, so you can deliver a value to it.
$promise->deliver('foo');
This code is broken because the deliver
method is not defined, and will throw a PHP fatal error, but we can find this example in the documentation.
I'm doing some integration testing with a library and use guzzle to make an async http request and noticed that my tests were always passing even when that is not expected. Through debugging narrowed down the issue to being caused by the fact that an exception thrown from a then
in a promise won't stop the system from running.
In the snippet bellow for instance, I'm able to get the log in the error.log but PHPUnit never gets the exception when running the unit test. I also tried running this in isolation outside of the unit testing context and same behavior is exhibited
$promise = $httpClient->requestAsync('GET', 'http://some-api-url');
$promise->then(
function ($response) {
error_log('Exceptions thrown in promise do not bubble-up');
throw new Exception('Invalid hit sent. got response: ' . $response->getBody());
},
function ($exception) {
// handle HTTP request exception
}
);
Is this behavior expected? Am I doing something wrong?
Thanks
The comments for FulfilledPromise indicate that any calls to then()
will invoke the callback immediately, but it seems to just add it to queue()
.
Is the documentation wrong or is this a bug?
If you have something like this:
$client = new Client();
$client->requestAsync('GET', 'http://example.com')->then(function($result) {
// This executes.
return 'Hello';
})->then(function($value) {
// This executes as well.
return $value . ' World!';
})->then(function($value) {
// This never executes.
return 'Never gonna give you up';
});
The reason for this is (from what I can tell) because Guzzle wraps the first handler in a promise, but it doesn't wrap anything else because this library does not wrap a then()
value.
I think it should be consistent either way, it was hard to debug why this was happening. Wrapping the second then()
in a new FullfilledPromise()
like this:
return new FullfilledPromise($value . ' World!');
fixed my problem.
I expected a value return in then()
to be wrapped in a promise all the time, so I think that's what should happen and it should be a trivial change and I don't think it should break anyone's apps (except for that promises that weren't ever executed will now be executed).
I do need that feature of conditionally loading the global functions due to messed up autoloading on my side.
The following code yields no response. Shouldn't it trigger the cancel()
method in the inner promise? Is this a bug or a feature?
$promise = new Promise();
$promise->resolve(true);
$promise
->then(function() {
return (new Promise())
->then(function() {
echo "inner-promise fulfilled!";
})
->otherwise(function() {
echo "inner-promise rejected!";
});
})
->then(function() {
echo "promise fulfilled!";
})
->otherwise(function() {
echo "promise rejected!";
})
->cancel();
\GuzzleHttp\Promise\queue()->run();
Latest 1.3.0
release includes coroutine
changes that seems break aws-sdk-php
behaviors.
coroutine
is used in our instanceCredentialProvider
, which is chained in our defaultCredentialProvider
This problem is related to guzzle because there has been no related code changes in our repo, and when downgrade to 1.2.0
fix the problem.
Personally, I'm having trouble in reproducing the issue locally or with a new ubuntu ec2 instance, and I'm still woking on reproducing it since many customer have reported seeing this issue happening.
Related issue:
aws/aws-sdk-php#1125
guzzle/guzzle#1668
Possible reproduce repo: https://github.com/reproduce/guzzle/tree/issue1668
Open this issue here as well just to have more attention, background and thoughts here. :)
I think it's useful to have task queue adapters (TaskQueueInterface
implementations) for popular event loops in the core, such as ReactPHP event loop.
Please tag a new release so that there's a stable version with Throwable
support.
Hi,
I'm attempting to do some unit testing using a class that utilizes the promises library. Here's the general approach (in a file MyTest.php):
use PHPUnit\Framework\TestCase;
use GuzzleHttp\Promise\FulfilledPromise;
class MyTest extends TestCase {
/**
* Tests unit testing with callbacks.
*/
public function testFoo() {
$p = new FulfilledPromise("");
$me = $this;
$p->then(function() use ($me) {
$me->assertTrue(TRUE, "Foo promise returning method succeeded.");
print (sprintf("%s::%s line %s: Success callback executed\n", get_class($this), __FUNCTION__, __LINE__));
}, function() use ($me) {
$me->assertTrue(FALSE, "Foo promise returning method succeeded.");
print (sprintf("%s::%s line %s: Failure callback executed\n", get_class($this), __FUNCTION__, __LINE__));
});
}
}
The test completes without any assertions occurring (at least, none whose output is recognized by the testing suite). It appears the callbacks execute after the unit test completes:
PHPUnit 5.2.9 by Sebastian Bergmann and contributors.
Runtime: PHP 5.6.18 with Xdebug 2.3.3
Configuration: [excluded]
. 1 / 1 (100%)
Time: 154 ms, Memory: 5.25Mb
OK (1 test, 0 assertions)
MyTest::{closure} line 91: Success callback executed
Do you know of a decent approach to using PHPUnit with Guzzle promises?
I don't get it how is this useful if it doesn't work async? The whole point of promises is to execute code async... so like wtf?
The code works if i do $promise->wait();, however i am not sure how can i call the promise to work async.
foreach ($entries as $key=>$value)
{
$promise = new Promise(function() use (&$promise, $key, $value)
{
// Do some heavy lifting work.
$mainOutput = array($key, $output, $value);
$promise->resolve($mainOutput);
});
$promise->then(
// $onFulfilled
function ($mainOutput)
{
static::addToResponse($mainOutput);
},
// $onRejected
function ($reason)
{
echo 'The promise was rejected.';
}
);
if(static::$sync)
{
$promise->wait();
}
else
{
}
}
Hey there,
I've got the following code:
$promise->then(
// $onFulfilled
function ($user) {
// bla bla
},
// $onRejected
function ($reason) {
throw new Error('reset_password_token_expired');
}
);
but the error is being caught.
What can I do to allow it to propagate up the error chain and crash the app?
Thank you
Hello,
Guzzle's all($promises)
function should be recursive: resolution of $promises
may add new promises into the $promises
stack. These new promises should not be left pending.
I'm using Guzzle's all()
function to resolve a collection of promises, stored in an iterator.
What if one of these promises, when resolved, adds a new promise to the stack?
Have a look at the following code:
$data = new ArrayObject();
$promises = new ArrayIterator();
$promises[] = $fooPromise = new \GuzzleHttp\Promise\Promise(function () use ($promises, &$fooPromise, $data) {
var_dump('Loading foo');
$data[] = 'foo';
$fooPromise->resolve('foo');
});
$fooPromise->then(function () use (&$promises, $data) {
# When $fooPromise is resolved, for some reason I may add some data with another promise
$barPromise = new \GuzzleHttp\Promise\Promise(function () use ($promises, &$barPromise, $data) {
var_dump('Loading bar');
$data[] = 'bar';
$barPromise->resolve('bar');
});
$promises[] = $barPromise;
});
$mainPromise = \GuzzleHttp\Promise\all($promises);
$mainPromise->wait();
var_dump($data->getArrayCopy());
I expect the following output:
string(11) "Loading foo"
string(11) "Loading bar"
array(2) {
[0]=>
string(3) "foo"
[1]=>
string(3) "bar"
}
But I get this:
string(11) "Loading foo"
array(1) {
[0]=>
string(3) "foo"
}
And my $secondPromise
state is pending
. Why is it not resolved?
Thank you,
Ben
It suggests the following as event loop integration for ReactPHP:
$loop = React\EventLoop\Factory::create();
$loop->addPeriodicTimer(0, [$queue, 'run']);
That will basically be an infinite loop that always calls [$queue, 'run']
and hogs the CPU until the entire thing is done. A better way would be a short timer like 10 milliseconds. It's not as responsive, but at least it doesn't consume 100% CPU.
Hi everyone,
Make promise resolution simpler:
$promise = new \GuzzleHttp\Promise\Promise(function () use (&$promise) {
$promise->resolve('The referenced promise has been resolved');
});
to:
$promise = new \GuzzleHttp\Promise\Promise(function (PromiseInterface $promise) {
$promise->resolve('The promise has been resolved');
});
Actually, when you create a promise from scratch you must use a reference to that promise within the wait function, i.e.:
$promise = new \GuzzleHttp\Promise\Promise(function () use (&$promise) {
$promise->resolve('The referenced promise has been resolved');
});
From a DX point of view, this can lead to headaches when it comes to generate promises within a loop. Let's take this as an example:
use GuzzleHttp\Promise\Promise;
use function GuzzleHttp\Promise\all;
require_once __DIR__ . '/vendor/autoload.php';
$translationMap = [
'banana' => 'banane',
'apple' => 'pomme',
];
$fruits = [
'banana',
];
$promises = [];
foreach ($fruits AS $fruit) {
$promises[$fruit] = $promise = new Promise(function () use (&$promise, $translationMap, $fruit) {
$promise->resolve($translationMap[$fruit]);
});
}
var_dump(all($promises)->wait()); // Expected ['banana' => 'banane'] and indeed got ['banana' => 'banane']
In this example, there's only 1 instance of $promise
, and everything's fine. Now add an apple
into the $fruits
array:
use GuzzleHttp\Promise\Promise;
use function GuzzleHttp\Promise\all;
require_once __DIR__ . '/vendor/autoload.php';
$translationMap = [
'banana' => 'banane',
'apple' => 'pomme',
];
$fruits = [
'banana',
'apple',
];
$promises = [];
foreach ($fruits AS $fruit) {
$promises[$fruit] = $promise = new Promise(function () use (&$promise, $translationMap, $fruit) {
$promise->resolve($translationMap[$fruit]);
});
}
var_dump(all($promises)->wait()); // Expected ['banana' => 'banane', 'apple' => 'pomme']
// But got GuzzleHttp\Promise\RejectionException: Invoking the wait callback did not resolve the promise...
Of course, this RejectionException
would not happen if I chose a different variable name for each $promise
. But honestly this is ugly.
A simpler solution would be to pass the promise itself directly as an argument into the wait function, instead of relying on a reference, i.e:
$promise = new \GuzzleHttp\Promise\Promise(function (PromiseInterface $promise) {
$promise->resolve('The promise has been resolved');
});
This would require a change into the Promise::invokeWaitFn()
method:
$wfn($this);
// instead of
$wfn(true);
This would simplify a lot the promise resolution.
What's your opinion ?
Hi,
I'd just like to make a request about this bit of code in FulfilledPromise:
if (method_exists($value, 'then')) {
throw new \InvalidArgumentException(
'You cannot create a FulfilledPromise with a promise.');
}
Is there any chance you could change that first line to:
if ($value instanceof 'GuzzleHttp\Promise\PromiseInterface')){
I'm trying to pass a non-promise object as an argument, and it's bailing because my object has a 'then' method.
I can't seem to find a "core" answer that is really important to me, sorry if obvious/written but how does a core promise object can work async? Does it pops a new php process on the server or separate thread?
Thks for the hints.
the thenable cannot omit the value for resolve().
PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function GuzzleHttp\Promise\Promise::resolve(), 0 passed
but it's very useful for just resolve the promise without returning the value.
For ReactPHP and nodejs, we can omit the resolve value and just resolve the promise directly.
How can I unwrap a promise when integrated with Event Loop?
Please see https://github.com/reactphp/promise#done-vs-then
How can I have "done" in guzzle/promises?
I need this feature in Event Loop Integration
Calling done() transfers all responsibility for errors to your code. If an error (either a thrown exception or returned rejection) escapes the $onFulfilled or $onRejected callbacks you provide to done, it will be rethrown in an uncatchable way causing a fatal error.
Disclaimer: This is not a bug, this is just a question.
I have created a web client for a particular API. I also created a Middleware for handling exceptions, the code looks like this:
class ErrorHandlerMiddleware {
public static function create() {
return function (callable $handler) {
return function ($request, array $options) use ($handler) {
if ($options['http_errors']) {
return $handler($request, $options);
}
return $handler($request, $options)->then(
function (ResponseInterface $response) use ($request, $handler) {
$code = $response->getStatusCode();
if ($code < 400) {
return $response;
}
switch ($code) {
// ....
case '401':
throw new AccessDeniedException('Access Denied', $request, $response);
//...
}
},
function (RequestException $e) use ($request, $handler) {
throw new ConnectException('Service not working', $request);
}
);
};
};
}
}
My testing strategy is to create a dummy response object and set the status code to say 401 and then assert that an AccessDeniedException is thrown.
This is what I've done in my unit test
public function testFoo() {
$options = [
'http_errors' => false
];
$request = new \GuzzleHttp\Psr7\Request('get', 'http://foo.com');
$handler = function($request, $options) {
return new GuzzleHttp\Promise\Promise();
};
$middleware = ErrorHandlerMiddleware::create();
$request_processor = $middleware($handler);
$promise = $request_processor($request, $options);
}
According to the documentation I need to "resolve" the promise so that I get my callback.
Question 1: How do I use my dummy $response object with the callback defined in the promise?
I tried something like this
$resolved = $promise->resolve('return new \GuzzleHttp\Psr7\Response(200)');
var_dump($resolved());
But I get this error message: "Function name must be a string"
Question 2: It seems like "resolve" only accepts strings, if that's the case, How Am I supposed to use my $response object inside the promise?
I would like to propose a change for better event loop integration.
The issues
Current way for event loop integration (using addPeriodicTimer
or futureTick
) leads to 100% CPU load, because it kills the whole idea. There is always something to do (run the promises queue), so the timeout before the next tick is always 0 or near it.
It also leads to an endless event loop, because, again, there is always something to do.
The proposed solution
Make the TaskQueue changeable in the code, to be able to set a proper implementation in case of an event loop. A simple event loop implementation could do $loop->nextTick([$queue, 'run'])
inside the add()
method, so only when it's needed.
I think it can be done with
TaskQueueInterface
that will contain all methods from the current TaskQueue
,TaskQueue::getInstance()
and TaskQueue::setInstance(TaskQueueInterface $q)
methods,queue()
inside the code to TaskQueue::getInstance()
.This way doesn't require BC breaks.
What do you think about it?
I don't really understand can I implement producer-consumer scheme using this library?
For example, imagine a producing function which makes some values over time, and another consuming function which takes the values. Is there a way to implement this using Promises?
It runs promise callbacks on php script shutdown.. So all the promises will be executed one by one..
i want to know if it really works parallel
Fatal error: Interface 'GuzzleHttp\Promise\TaskQueueInterface' not found in vendor/guzzlehttp/promises/src/TaskQueue.php on line
13
Can someone explain how this can be solved ?
I was just writing some code that would have been greatly improved by having a splat()
function that works similarly to all()
.
The current code is:
Promise\all($promises)->then(function ($results) {
list($first, $second) = $results;
...
});
But what I would rather write is:
Promise\splat($promises)->then(function ($first, $second) {
...
});
This would require PHP >= 5.6 for argument unpacking or the use of call_user_func_array
.
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.