public function index() { $promises = call_user_func(function () { foreach ($this->usernames as $username) { (yield $this->client->requestAsync('GET', 'https://api.github.com/users/' . $username)); } }); // Wait till all the requests are finished. \GuzzleHttp\Promise\all($promises)->then(function (array $responses) { $this->profiles = array_map(function ($response) { return json_decode($response->getBody(), true); }, $responses); })->wait(); // Return JSON response $response = new Response(); // StreamInterface objects are not immutable! $response->getBody()->write($this->html()); return $response->withHeader('Content-type', 'text/html'); }
/** * @return static */ public function index() { $promises = array_map(function ($username) { $url = 'https://api.github.com/users/' . $username; return $this->client->sendAsync(new Request('GET', $url)); // return $this->client->requestAsync('GET', $url); }, $this->usernames); // Wait till all the requests are finished. \GuzzleHttp\Promise\all($promises)->then(function (array $responses) { $this->profiles = array_map(function ($response) { return json_decode($response->getBody(), true); }, $responses); })->wait(); // Return JSON response $response = new \Zend\Diactoros\Response(); // StreamInterface objects are not immutable! $response->getBody()->write(json_encode($this->profiles)); return $response->withHeader('Content-Type', 'application/json'); }
public function testAllThrowsWhenAnyRejected() { $a = new Promise(); $b = new Promise(); $c = new Promise(); $d = \GuzzleHttp\Promise\all([$a, $b, $c]); $b->resolve('b'); $a->reject('fail'); $c->resolve('c'); $d->then(function ($value) use(&$result) { $result = $value; }, function ($reason) use(&$result) { $result = $reason; }); P\queue()->run(); $this->assertEquals('fail', $result); }
public static function destroyAsync($ids) { // We'll initialize a count here so we will return the total number of deletes // for the operation. The developers can then check this number as a boolean // type value or get this total count of records deleted for logging, etc. $ids = is_array($ids) ? $ids : func_get_args(); // We will actually pull the models from the database table and call delete on // each of them individually so that their events get fired properly with a // correct set of attributes in case the developers wants to check these. $tasks = []; foreach ($ids as $id) { if ($model = static::find($id)) { $tasks[] = $model->deleteAsync($id); } } return \GuzzleHttp\Promise\all($tasks)->then(function ($results) { $count = 0; foreach ($results as $result) { if ($result) { $count++; } } return $count; }); }
public function onKernelController(FilterControllerEvent $event) { if (!$event->isMasterRequest()) { return; } $request = $event->getRequest(); if (!$request->attributes->has('_api')) { return; } /** @var Api $api */ $api = $request->attributes->get('_api'); $subRequests = $this->getSubRequests($request); $bulk = $api->isBulkable() && $subRequests; $stream = ($api->isStreamable() || $bulk) && $this->shouldStream($request); if (!$bulk && !$stream) { $request->attributes->set('stream', $this->noop); return; } // This listener will unwind/spread the calls, so don't trigger other Api listeners. $request->attributes->remove('_api'); if ($stream) { $headers = ['content-type' => 'application/json; boundary=NL', 'x-accel-buffering' => 'no']; } else { $headers = ['content-type' => 'application/json']; } if ($subRequests) { $event->setController(function () use($request, $headers, $subRequests, $stream) { return new StreamedResponse(function () use($request, $subRequests, $stream) { $promises = []; foreach ($subRequests as $i => $requestParams) { // Forward the query string without the 'payload', and put all the parameters in the body. $query = $request->query->all(); if (isset($query['payload'])) { unset($query['payload']); } $subRequest = $request->duplicate([], $requestParams); // Also force-make it a POST request, so it can contain a body. $subRequest->setMethod('POST'); $subRequest->attributes->set('stream', $stream ? $this->createStreamer($i) : $this->noop); /* @var PromiseInterface $promise */ $promises[] = $promise = $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true, false); if ($stream) { $streamer = $this->createStreamer($i); $promise->then(function (Response $response) use($streamer) { $streamer($response->getContent(), true); }); } } $responses = \GuzzleHttp\Promise\all($promises)->wait(); if (!$stream) { echo '['; for (reset($responses); $response = current($responses); next($responses)) { echo $response->getContent(); if (current($responses)) { echo ','; } } echo ']'; } }, 200, $headers); }); } else { $event->setController(function () use($request, $headers) { return new StreamedResponse(function () use($request) { $request->attributes->set('stream', $this->createStreamer()); // We duplicate the request because the profiler component's token keeps a reference to the parent request's token, // creating an infinite loop when attempting to display profiler info. $response = $this->httpKernel->handle($request->duplicate(), HttpKernelInterface::SUB_REQUEST, true, true); // The streamer outputs a new line as the ending delimiter. In single action calls, the ending line should be // the actual response without a new line at the end. That's why streaming single calls have a resulting // response, but bulk calls don't have one. echo $response->getContent(); }, 200, $headers); }); } }
/** * Creates a Dynamic Large Object by chunking a file into smaller segments and uploading them into a holding * container. When this completes, a manifest file is uploaded which references the prefix of the segments, * allowing concatenation when a request is executed against the manifest. * * @param array $data {@see \OpenStack\ObjectStore\v1\Api::putObject} * @param int $data['segmentSize'] The size in Bytes of each segment * @param string $data['segmentContainer'] The container to which each segment will be uploaded * @param string $data['segmentPrefix'] The prefix that will come before each segment. If omitted, a default * is used: name/timestamp/filesize * * @return Object */ public function createLargeObject(array $data) { /** @var \Psr\Http\Message\StreamInterface $stream */ $stream = $data['stream']; $segmentSize = isset($data['segmentSize']) ? $data['segmentSize'] : 1073741824; $segmentContainer = isset($data['segmentContainer']) ? $data['segmentContainer'] : $this->name . '_segments'; $segmentPrefix = isset($data['segmentPrefix']) ? $data['segmentPrefix'] : sprintf("%s/%s/%d", $data['name'], microtime(true), $stream->getSize()); /** @var \OpenStack\ObjectStore\v1\Service $service */ $service = $this->getService(); if (!$service->containerExists($segmentContainer)) { $service->createContainer(['name' => $segmentContainer]); } $promises = []; $count = 0; while (!$stream->eof() && $count < round($stream->getSize() / $segmentSize)) { $promises[] = $this->model(Object::class)->createAsync(['name' => sprintf("%s/%d", $segmentPrefix, ++$count), 'stream' => new LimitStream($stream, $segmentSize, ($count - 1) * $segmentSize), 'containerName' => $segmentContainer]); } /** @var Promise $p */ $p = \GuzzleHttp\Promise\all($promises); $p->wait(); return $this->createObject(['name' => $data['name'], 'objectManifest' => sprintf("%s/%s", $segmentContainer, $segmentPrefix)]); }
/** * @dataProvider requestList */ public function testQueueLimitsNumberOfProcessingRequests(array $queueData, $expectedDuration, $throttleLimit, $threshold = 0.05) { $handler = new HandlerStack(new LoopHandler()); $handler->push(ThrottleMiddleware::create()); $client = new \GuzzleHttp\Client(['handler' => $handler, 'base_uri' => Server::$url, 'timeout' => 10]); $queueEnd = $promises = $responses = $expectedStart = []; Server::start(); Server::enqueue(array_fill(0, count($queueData), new Response())); foreach ($queueData as $queueItem) { list($queueId, $requestDuration, $expectedStartTime) = $queueItem; $options = [RequestOptions::HTTP_ERRORS => false, RequestOptions::HEADERS => ['duration' => $requestDuration], 'throttle_id' => $queueId, 'throttle_limit' => $throttleLimit]; $expectedStart[$queueId] = $expectedStartTime; $promises[] = $client->getAsync('', $options)->then(function () use($queueId, &$queueStart, &$queueEnd) { if (!isset($queueStart[$queueId])) { $queueStart[$queueId] = microtime(true); } $queueEnd[$queueId] = microtime(true); }); } $start = microtime(true); $GLOBALS['s'] = microtime(1); \GuzzleHttp\Promise\all($promises)->wait(); $duration = microtime(true) - $start; $this->assertGreaterThan($expectedDuration - $threshold, $duration); $this->assertLessThan($expectedDuration + $threshold, $duration); foreach ($queueEnd as $i => $endedAt) { $duration = $endedAt - $start; // $this->assertGreaterThan($expectedDuration - $threshold, $endedAt - $start, "Queue #$i started too soon"); // $this->assertLessThan($queueInfo->getExpectedDuration() + $threshold, $queueInfo->getDuration(), "Queue #$i started too late"); // // $this->assertGreaterThan($started + $queueInfo->getExpectedDelay() - $threshold, $queueInfo->getStartedAt(), "Queue #$i popped too early"); // $this->assertLessThan($started + $queueInfo->getExpectedDelay() + $threshold, $queueInfo->getStartedAt(), "Queue #$i popped too late"); } }