I want to use guzzle http for ping.
I dont care about the response.
Just request is enough.
No need of response.
After request the code need to exits. Dont wait for response.
I tried to do with async.
<?php
require_once "vendor/autoload.php";
$client = new GuzzleHttp\Client();
$promise1 = $client->requestAsync('GET', 'http://localhost/test/?id=from_async1');
$promise2 = $client->requestAsync('GET', 'http://localhost/test/?id=from_async2');
$promise3 = $client->requestAsync('GET', 'http://localhost/test/?id=from_async3');
$promise1->then(function (ResponseInterface $response) {
});
$promise2->then(function (ResponseInterface $response) {
});
$promise3->then(function (ResponseInterface $response) {
});
$promise1->wait();
$promise2->wait();
$promise3->wait();
But still this script waits for all response to come back.
How to get the script work without waiting for response? Any thoughts?
Related
test.php
<?php
//simulate different blocking times
if(isset($_GET['appid'])) {
sleep(rand(3, 10));
echo $_GET['appid'];
exit;
}
client.php
<?php
require './vendor/autoload.php';
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Client;
$client = new Client();
$promise = null;
$loop = function ($appId) use($client, &$loop, &$promise) {
$promise = $client->getAsync("http://127.0.0.1/test.php?appid={$appId}");
$promise->then(
function (ResponseInterface $res) use(&$loop, $appId) {
echo $res->getBody();
//After completing the current request, initiate the request again to simulate EventLoop
$loop($appId);
},
function (RequestException $e) use(&$loop, $appId) {
//Ignore the error and continue to simulate EventLoop
$loop($appId);
}
);
};
foreach(range(1, 10) as $appId) {
$loop($appId);
}
$promise->wait();
I try to use promise to simulate EventLoop. As shown in my example code, I have 10 application IDs. I want to launch 10 requests concurrently. At the same time, the response time of each request is different. I want to launch the request of the current application ID immediately after each request is completed to simulate EventLoop.
But I find it doesn't seem to work. How can I simulate EventLoop
I'm trying to send a request to an endpoint, but I don't want to wait for them to respond, as I don't need the response. So I'm using Guzzle, here's how:
$url = 'http://example.com';
$client = new \Guzzelhttp\Client();
$promise = $client->postAsync($url, [
'headers' => ['Some headers and authorization'],
'query' => [
'params' => 'params',
]
])->then(function ($result) {
// I don't need the result. So I just leave it here.
});
$promise->wait();
A I understood, I have to call the wait method on the client in order to actually send the request. But it's totally negates the request being "async" because if the url was not accessible or the server was down, the application would wait for a timeout or any other errors.
So, the question here is, what does Guzzle mean by "async" when you have to wait for the response anyway? And how can I call a truly async request with PHP?
Thanks
What you can do is:
$url = 'http://example.com';
$client = new \Guzzelhttp\Client();
$promise = $client->postAsync($url, [
'headers' => ['Some headers and authorization'],
'query' => [
'params' => 'params',
]
])->then(function ($result) {
return $result->getStatusCode();
})
->wait();
echo $promise;
You need the wait() to be called as the last line so you get the result which will come from your promise.
In this case it will return just the status code.
Just as mentioned in Github is not able to "fire and forget"so i think what you are trying to achieve, like a complete promise like in Vue or React won't work for you here the way you want it to work.
Another approach and what i do personally is to use a try-catch on guzzle requests, so if there is a guzzle error then you catch it and throw an exception.
Call then() method if you don't want to wait for the result:
$client = new GuzzleClient();
$promise = $client->getAsync($url)
$promise->then();
Empty then() call will make an HTTP request without waiting for result, Very similar to
curl_setopt(CURLOPT_RETURNTRANSFER,false)
use Illuminate\Support\Facades\Http;
...Some Code here
$prom = Http::timeout(1)->async()->post($URL_STRING, $ARRAY_DATA)->wait();
... Some more important code here
return "Request sent"; //OR whatever you need to return
This works for me as I don't need to know the response always.
It still uses wait() but because of the small timeout value it doesn't truly wait for the response.
Hope this helps others.
I am using guzzle to send some requests:
$response = $this->client->request(new SomeObject());
using the class below
...
public function request(Request $request)
{
return $this->requestAsync($request)->wait();
}
// Here I'm using Guzzle Async, but I can remove that is needed
public function requestAsync(Request $request)
{
$promise = $this->http->requestAsync($request->getMethod(), $request->getUri());
$promise = $promise->then(
function (ResponseInterface $response) use ($request) {
return $response;
}
);
return $promise;
}
...
I would like to use ReactPHP to send multiple requests at once in a foreach loop:
$requests = [];
foreach ($data as $value) {
$requests[] = $this->client->request(new SomeObject());
}
// pass $requests to ReactPHP here and wait on the response
Any ideas?
First of all, you don't need ReactPHP to use parallel HTTP requests with Guzzle. Guzzle itself provides this feature (if you use cURL handler, which is the default).
For example:
$promises = [];
foreach ($data as $value) {
$promises[] = $guzzleClient->getAsync(/* some URL */);
}
// Combine all promises
$combinedPromise = \GuzzleHttp\Promise\all($promises)
// And wait for them to finish (all requests are executed in parallel)
$responses = $combinedPromise->wait();
If you still want to use Guzzle with ReactPHP event loop, then, unfortunately, there are no straightforward solution. You cat take a look at https://github.com/productsupcom/guzzle-react-bridge (I'm the developer, so feel free to ask questions).
I'm trying to understand the concept of Promises using ReactPHP
$app = function ($request, $response) use ($redis, $config) {
$promise = React\Promise\all(
array(
AsyncGetUser(),
AsyncGetDB(),
AsyncGetTemplate()
)
)->then(function ($res) {
$result = ParseTemplate($user, $template, $whatever);
}
\React\Promise\resolve($promise);
$response->writeHead(200, array('Content-Type' => 'text/plain'));
$response->end($result);
}
$http->on('request', $app);
But $response is sent before $result is ready.
How can do something like await for $promise so I send $result properly ?
I've tried to move $response->end to another->then() section but then I don't get any response in browser (i.e. the script gets a result when $app = function is finished already).
I don't know reactphp at all, but if promises work like promises in JS for example, seems like you need to write the response in the ->then where you have a result!
$app = function ($request, $response) use ($redis, $config) {
$promise = React\Promise\all(
array(
AsyncGetUser(),
AsyncGetDB(),
AsyncGetTemplate()
)
)->then(function ($res) {
$result = ParseTemplate($user, $template, $whatever);
$response->writeHead(200, array('Content-Type' => 'text/plain'));
$response->end($result);
}
}
$http->on('request', $app);
Note: the following line in your code
\React\Promise\resolve($promise);
makes no sense. \React\Promise\resolve doesn't "resolve the promise" as you seem to think, it creates and returns a resolved promise - which you discard!
If somethings goes bad in my API i want to return a http 500 request.
$app = new Slim();
$app->halt(500);
It still return a http 200.
If i run this code:
$status = $app->response()->status();
echo $status; //Here it is 200
$status = $app->response()->status(500);
echo $status; //Here it is 500
it stills give me a http 200
The $app->response()->status(500); is correct, see the docs here.
Check to make sure you're calling $app->run(); after setting the status, this will prepare and output the response code, headers and body.
Edit, make sure you define a route or Slim will output the 404 response, this works:
require 'Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
$app->response()->status(500);
$app->get('/', function () {
// index route
});
$app->run();
If anyone still has this issue here is what I ended up doing:
Setup an error handler
$app->error(function (Exception $exc) use ($app) {
// custom exception codes used for HTTP status
if ($exc->getCode() !== 0) {
$app->response->setStatus($exc->getCode());
}
$app->response->headers->set('Content-Type', 'application/json');
echo json_encode(["error" => $exc->getMessage()]);
});
then, anytime you need to return a particular HTTP status throw an Exception with the status code included:
throw new Exception("My custom exception with status code of my choice", 401);
(Found it on the Slim forum)
If you have to push header after $app->run(), you can always rely on the header php function:
header('HTTP/1.1 401 Anonymous not allowed');
Slim framework v2 wiki status
require 'Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
$app->get('/', function () use ($app) {
$app->response()->setStatus(500);
$app->response()->setBody("responseText");
return $app->response();
});
$app->run();
or
$app->get('/', function () use ($app) {
$app->halt(500, "responseText");
});