/** * @return array Data for testTransfersBatches */ public function getTransferBatchesData() { // Mock objects for 3rd test case $mockRequest = $this->getMockBuilder('Guzzle\\Http\\Message\\EntityEnclosingRequestInterface')->disableOriginalConstructor()->getMock(); $mockRequest->expects($this->any())->method('getBody')->will($this->onConsecutiveCalls('{"RequestItems":{"foo":[{"PutRequest":{}},{"PutRequest":{}}]}}', '{"RequestItems":{}}', '{"RequestItems":{}}')); $mockResponse = $this->getMockBuilder('Guzzle\\Http\\Message\\Response')->disableOriginalConstructor()->getMock(); $mockResponse->expects($this->any())->method('getStatusCode')->will($this->returnValue(413)); $tooBigException = new DynamoDbException(); $tooBigException->setResponse($mockResponse); $tooBigException->setRequest($mockRequest); $exceptionCollection = new ExceptionCollection(); $exceptionCollection->add($tooBigException); // Mock objects for 4th use case $exceptionCollectionWithDummy = new ExceptionCollection(); $exceptionCollectionWithDummy->add(new \RuntimeException()); // Provisioned throughput exceeded use case (#6) $throughputExceededException = new DynamoDbException(); $throughputExceededException->setExceptionCode('ProvisionedThroughputExceededException'); $mockRequestPTE = $this->getMockBuilder('Guzzle\\Http\\Message\\EntityEnclosingRequestInterface')->disableOriginalConstructor()->getMock(); $mockRequestPTE->expects($this->any())->method('getBody')->will($this->returnValue('{"RequestItems":{"foo":[{"PutRequest":{}},{"PutRequest":{}}]}}')); $throughputExceededException->setRequest($mockRequestPTE); $exceptionCollectionThroughput = new ExceptionCollection(); $exceptionCollectionThroughput->add($throughputExceededException); // Some DynamoDbException that will be rethrown, not handled (case #7) $unhandledDynamoDbException = new DynamoDbException(); $unhandledDynamoDbException->setExceptionCode('UnhandledException'); $exceptionCollectionUnhandled = new ExceptionCollection(); $exceptionCollectionUnhandled->add($unhandledDynamoDbException); return array(array(array('UnprocessedItems' => array()), null, 'all-items-transferred'), array(array('UnprocessedItems' => array('foo' => array(array('foo')))), null, 'some-unprocessed-items'), array(array('UnprocessedItems' => array()), $this->throwException($exceptionCollection), 'all-items-transferred'), array(array('UnprocessedItems' => array()), $this->throwException($exceptionCollectionWithDummy), 'exceptions-thrown'), array(array('UnprocessedItems' => array()), $this->throwException($exceptionCollectionWithDummy), 'exceptions-thrown'), array(array('UnprocessedItems' => array()), $this->throwException($exceptionCollectionThroughput), 'some-unprocessed-items'), array(array('UnprocessedItems' => array()), $this->throwException($exceptionCollectionUnhandled), 'exceptions-thrown')); }
public function testCanAddSelf() { $e1 = new ExceptionCollection(); $e1->add(new \Exception("Test")); $e2 = new ExceptionCollection(); $e2->add(new \Exception("Test 2")); $e1->add($e2); $this->assertEquals("Test\nTest 2", $e1->getMessage()); }
public function testCanAddSelf() { $e1 = new ExceptionCollection(); $e1->add(new \Exception("Test")); $e2 = new ExceptionCollection('Meta description!'); $e2->add(new \Exception("Test 2")); $e3 = new ExceptionCollection(); $e3->add(new \Exception('Baz')); $e2->add($e3); $e1->add($e2); $message = $e1->getMessage(); $this->assertEquals("(Exception) Test\n" . "(Guzzle\\Common\\Exception\\ExceptionCollection)\n" . " Meta description!\n" . " (Exception) Test 2\n" . " (Guzzle\\Common\\Exception\\ExceptionCollection)\n" . " (Exception) Baz", $message); }
/** * Add exceptions to the collection * * @param ExceptionCollection|\Exception $e Exception to add * * @return ExceptionCollection; */ public function add($e) { if ($e instanceof self) { foreach ($e as $exception) { $this->exceptions[] = $exception; } } elseif ($e instanceof \Exception) { $this->exceptions[] = $e; } $this->message = implode("\n", array_map(function ($e) { return $e->getMessage(); }, $this->exceptions)); return $this; }
/** * Transfer a batch of requests and collect any unprocessed items * * @param array $batch A batch of write requests * @param UnprocessedWriteRequestsException $unprocessedRequests Collection of unprocessed items * * @throws \Guzzle\Common\Exception\ExceptionCollection */ protected function performTransfer(array $batch, UnprocessedWriteRequestsException $unprocessedRequests) { // Do nothing if the batch is empty if (empty($batch)) { return; } // Prepare an array of commands to be sent in parallel from the batch $commands = $this->prepareCommandsForBatchedItems($batch); // Execute the commands and handle exceptions try { $commands = $this->client->execute($commands); $this->getUnprocessedRequestsFromCommands($commands, $unprocessedRequests); } catch (ExceptionCollection $exceptions) { // Create a container exception for any unhandled (true) exceptions $unhandledExceptions = new ExceptionCollection(); // Loop through caught exceptions and handle RequestTooLarge scenarios /** @var $e DynamoDbException */ foreach ($exceptions as $e) { if ($e instanceof DynamoDbException) { $request = $e->getRequest(); if ($e->getStatusCode() === 413) { $this->retryLargeRequest($request, $unprocessedRequests); } elseif ($e->getExceptionCode() === 'ProvisionedThroughputExceededException') { $this->handleUnprocessedRequestsAfterException($request, $unprocessedRequests); } } else { $unhandledExceptions->add($e); } } // If there were unhandled exceptions, throw them if (count($unhandledExceptions)) { throw $unhandledExceptions; } } }
public function testCanAddSelf() { $e1 = new ExceptionCollection(); $e1->add(new \Exception("Test")); $e2 = new ExceptionCollection('Meta description!'); $e2->add(new \Exception("Test 2")); $e3 = new ExceptionCollection(); $e3->add(new \Exception('Baz')); $e2->add($e3); $e1->add($e2); $message = $e1->getMessage(); $this->assertContains("(Exception) ./tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php line ", $message); $this->assertContains("\n Test\n\n #0 ", $message); $this->assertContains("\n\n(Guzzle\\Common\\Exception\\ExceptionCollection) ./tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php line ", $message); $this->assertContains("\n\n Meta description!\n\n", $message); $this->assertContains(" (Exception) ./tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php line ", $message); $this->assertContains("\n Test 2\n\n #0 ", $message); $this->assertContains(" (Exception) ./tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php line ", $message); $this->assertContains(" Baz\n\n #0", $message); }
/** * {@inheritdoc} */ public function send() { $this->scope++; // Don't prepare for sending again if send() is called while sending if ($this->state != self::STATE_SENDING) { $requests = $this->all(); // Any exceptions thrown from this event should break the entire // flow of sending requests in parallel to prevent weird errors $this->dispatch(self::BEFORE_SEND, array('requests' => $requests)); $this->state = self::STATE_SENDING; foreach ($requests as $request) { if ($request->getState() != RequestInterface::STATE_TRANSFER) { $this->beforeSend($request); } } } try { $this->perform(); } catch (\Exception $e) { $this->exceptions[] = $e; } $this->scope--; // Complete the transfer if this is the bottom scope and the state // of the curl multi handle is not already complete if ($this->state !== self::STATE_COMPLETE && $this->scope == -1) { $this->state = self::STATE_COMPLETE; $this->dispatch(self::COMPLETE); $this->state = self::STATE_IDLE; } if (!empty($this->exceptions)) { $collection = new ExceptionCollection('Errors during multi transfer'); while ($e = array_shift($this->exceptions)) { $collection->add($e); } $this->reset(); throw $collection; } }
/** * Clear the bucket * * @return int Returns the number of deleted keys * @throws ExceptionCollection */ public function clear() { $that = $this; $batch = DeleteObjectsBatch::factory($this->client, $this->bucket, $this->mfa); $batch = new NotifyingBatch($batch, function ($items) use($that) { $that->dispatch(ClearBucket::AFTER_DELETE, array('keys' => $items)); }); $batch = new FlushingBatch(new ExceptionBufferingBatch($batch), 1000); // Let any listeners know that the bucket is about to be cleared $this->dispatch(self::BEFORE_CLEAR, array('iterator' => $this->getIterator(), 'batch' => $batch, 'mfa' => $this->mfa)); $deleted = 0; foreach ($this->getIterator() as $object) { if (isset($object['VersionId'])) { $versionId = $object['VersionId'] == 'null' ? null : $object['VersionId']; } else { $versionId = null; } $batch->addKey($object['Key'], $versionId); $deleted++; } $batch->flush(); // If any errors were encountered, then throw an ExceptionCollection if (count($batch->getExceptions())) { $e = new ExceptionCollection(); foreach ($batch->getExceptions() as $exception) { $e->add($exception->getPrevious()); } throw $e; } // Let any listeners know that the bucket was cleared $this->dispatch(self::AFTER_CLEAR, array('deleted' => $deleted)); return $deleted; }
/** * Transfer a batch of requests and collect any unprocessed items * * @param array $batch A batch of write requests * @param UnprocessedWriteRequestsException $unprocessedRequests Collection of unprocessed items * * @throws \Guzzle\Common\Exception\ExceptionCollection */ protected function performTransfer(array $batch, UnprocessedWriteRequestsException $unprocessedRequests) { // Do nothing if the batch is empty if (empty($batch)) { return; } // Chunk the array and prepare a set of parallel commands $commands = array(); foreach (array_chunk($batch, self::BATCH_WRITE_MAX_SIZE) as $chunk) { // Convert the request items into the format required by the client $items = array(); foreach ($chunk as $item) { if ($item instanceof AbstractWriteRequest) { /** @var $item AbstractWriteRequest */ $table = $item->getTableName(); if (!isset($items[$table])) { $items[$table] = array(); } $items[$table][] = $item->toArray(); } } // Create the BatchWriteItem request $commands[] = $this->client->getCommand('BatchWriteItem', array('RequestItems' => $items, Ua::OPTION => Ua::BATCH)); } // Execute the commands and handle exceptions try { $commands = $this->client->execute($commands); $this->getUnprocessedRequestsFromCommands($commands, $unprocessedRequests); } catch (ExceptionCollection $exceptions) { // Create a container exception for any unhandled (true) exceptions $unhandledExceptions = new ExceptionCollection(); // Loop through caught exceptions and handle RequestTooLarge scenarios /** @var $e DynamoDbException */ foreach ($exceptions as $e) { if ($e instanceof DynamoDbException && $e->getStatusCode() === 413) { $request = $e->getResponse()->getRequest(); $this->retryLargeRequest($request, $unprocessedRequests); } else { $unhandledExceptions->add($e); } } // If there were unhandled exceptions, throw them if (count($unhandledExceptions)) { throw $unhandledExceptions; } } }
/** * {@inheritdoc} */ public function send() { $this->scope++; $this->state = self::STATE_SENDING; // Only prepare and send requests that are in the current recursion scope // Only enter the main perform() loop if there are requests in scope if (!empty($this->requests[$this->scope])) { // Any exceptions thrown from this event should break the entire // flow of sending requests in parallel to prevent weird errors $this->dispatch(self::BEFORE_SEND, array('requests' => $this->requests[$this->scope])); foreach ($this->requests[$this->scope] as $request) { if ($request->getState() != RequestInterface::STATE_TRANSFER) { $this->beforeSend($request); } } try { $this->perform(); } catch (\Exception $e) { $this->exceptions[] = $e; } } $this->scope--; // Aggregate exceptions into an ExceptionCollection $exceptionCollection = null; if (!empty($this->exceptions)) { $exceptionCollection = new ExceptionCollection('Errors during multi transfer'); while ($e = array_shift($this->exceptions)) { $exceptionCollection->add($e); } } // Complete the transfer if this is not a nested scope if ($this->scope == -1) { $this->state = self::STATE_COMPLETE; $this->dispatch(self::COMPLETE); $this->reset(); } // Throw any exceptions that were encountered if ($exceptionCollection) { throw $exceptionCollection; } }