Skip to content

Commit

Permalink
Merge pull request #18 from bcrowe/retries
Browse files Browse the repository at this point in the history
Add optional max retries for collection CRUD operations
  • Loading branch information
bcrowe committed Feb 12, 2015
2 parents dffa75c + 592e766 commit df59e7b
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 49 deletions.
170 changes: 121 additions & 49 deletions src/League/Monga/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ class Collection
*/
protected $collection;

/**
* @var int Amount of times to retry CRUD operations for "not master"
*/
protected $maxRetries = 1;

/**
* Constructor, sets the MongoCollection instance.
*
Expand Down Expand Up @@ -56,6 +61,21 @@ public function setCollection(MongoCollection $collection)
return $this;
}

/**
* Set the max amount of times to retry CRUD operations in the case of
* "not master" exceptions.
*
* @param int $amount The amount of times
*
* @return object $this
*/
public function setMaxRetries($amount)
{
$this->maxRetries = $amount;

return $this;
}

/**
* Drops the current collection.
*
Expand Down Expand Up @@ -221,18 +241,29 @@ public function remove($criteria, $options = array())
throw new \InvalidArgumentException('Remove criteria must be an array.');
}

try {
$result = $this->collection->remove($criteria, $options);
} catch (MongoCursorException $e) {
// Retry "remove" in case of rediscovery latency issues
// in replica set failover. Error codes 10107, 13435, and 10058
// are MongoCursorException's "not master" errors.
if (in_array($e->getCode(), array(10107, 13435, 10058))) {
$maxRetries = $this->maxRetries;
$tries = 0;

do {
try {
$result = $this->collection->remove($criteria, $options);
} else {
throw $e;
break;
} catch (MongoCursorException $e) {
// Retry "save" in case of rediscovery latency issues
// in replica set failover. Error codes 10107, 13435, and 10058
// are MongoCursorException's "not master" errors.
if (in_array($e->getCode(), array(10107, 13435, 10058))) {
if ($tries === $maxRetries) {
throw $e;
} else {
$tries++;
continue;
}
} else {
throw $e;
}
}
}
} while ($tries <= $maxRetries);

return $result === true || (bool) $result['ok'];
}
Expand Down Expand Up @@ -323,21 +354,32 @@ public function findOne($query = array(), $fields = array())
*/
public function insert(array $data, $options = array())
{
$maxRetries = $this->maxRetries;
$tries = 0;

// Check whether we're dealing with a batch insert.
if (isset($data[0]) && is_array($data[0])) {
// Insert using batchInsert
try {
$result = $this->collection->batchInsert($data, $options);
} catch (MongoCursorException $e) {
// Retry "batchInsert" in case of rediscovery latency issues
// in replica set failover. Error codes 10107, 13435, and 10058
// are MongoCursorException's "not master" errors.
if (in_array($e->getCode(), array(10107, 13435, 10058))) {
do {
try {
$result = $this->collection->batchInsert($data, $options);
} else {
throw $e;
break;
} catch (MongoCursorException $e) {
// Retry "save" in case of rediscovery latency issues
// in replica set failover. Error codes 10107, 13435, and 10058
// are MongoCursorException's "not master" errors.
if (in_array($e->getCode(), array(10107, 13435, 10058))) {
if ($tries === $maxRetries) {
throw $e;
} else {
$tries++;
continue;
}
} else {
throw $e;
}
}
}
} while ($tries <= $maxRetries);

if (! $result || ! ($result === true || (bool) $result['ok'])) {
return false;
Expand All @@ -354,18 +396,26 @@ public function insert(array $data, $options = array())
return $result;
}

try {
$result = $this->collection->insert($data, $options);
} catch (MongoCursorException $e) {
if (in_array($e->getCode(), array(10107, 13435, 10058))) {
// Retry "insert" in case of rediscovery latency issues
do {
try {
$result = $this->collection->insert($data, $options);
break;
} catch (MongoCursorException $e) {
// Retry "save" in case of rediscovery latency issues
// in replica set failover. Error codes 10107, 13435, and 10058
// are MongoCursorException's "not master" errors.
$result = $this->collection->insert($data, $options);
} else {
throw $e;
if (in_array($e->getCode(), array(10107, 13435, 10058))) {
if ($tries === $maxRetries) {
throw $e;
} else {
$tries++;
continue;
}
} else {
throw $e;
}
}
}
} while ($tries <= $maxRetries);

if ($result === true || (bool) $result['ok']) {
return $data['_id'];
Expand Down Expand Up @@ -401,18 +451,29 @@ public function update($values = array(), $query = null, $options = array())

isset($query) || $query = array();

try {
$result = $this->collection->update($query, $values, $options);
} catch (MongoCursorException $e) {
// Retry "update" in case of rediscovery latency issues
// in replica set failover. Error codes 10107, 13435, and 10058
// are MongoCursorException's "not master" errors.
if (in_array($e->getCode(), array(10107, 13435, 10058))) {
$maxRetries = $this->maxRetries;
$tries = 0;

do {
try {
$result = $this->collection->update($query, $values, $options);
} else {
throw $e;
break;
} catch (MongoCursorException $e) {
// Retry "save" in case of rediscovery latency issues
// in replica set failover. Error codes 10107, 13435, and 10058
// are MongoCursorException's "not master" errors.
if (in_array($e->getCode(), array(10107, 13435, 10058))) {
if ($tries === $maxRetries) {
throw $e;
} else {
$tries++;
continue;
}
} else {
throw $e;
}
}
}
} while ($tries <= $maxRetries);

return $result === true || (bool) $result['ok'];
}
Expand All @@ -427,18 +488,29 @@ public function update($values = array(), $query = null, $options = array())
*/
public function save(&$document, $options = array())
{
try {
$result = $this->collection->save($document, $options);
} catch (MongoCursorException $e) {
// Retry "save" in case of rediscovery latency issues
// in replica set failover. Error codes 10107, 13435, and 10058
// are MongoCursorException's "not master" errors.
if (in_array($e->getCode(), array(10107, 13435, 10058))) {
$maxRetries = $this->maxRetries;
$tries = 0;

do {
try {
$result = $this->collection->save($document, $options);
} else {
throw $e;
break;
} catch (MongoCursorException $e) {
// Retry "save" in case of rediscovery latency issues
// in replica set failover. Error codes 10107, 13435, and 10058
// are MongoCursorException's "not master" errors.
if (in_array($e->getCode(), array(10107, 13435, 10058))) {
if ($tries === $maxRetries) {
throw $e;
} else {
$tries++;
continue;
}
} else {
throw $e;
}
}
}
} while ($tries <= $maxRetries);

return $result === true || (bool) $result['ok'];
}
Expand Down
9 changes: 9 additions & 0 deletions tests/CollectionTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ public function testSetCollection()
$this->collection->setCollection($original);
}

public function testSetMaxRetries()
{
$this->collection->setMaxRetries(5);
$reflection = new ReflectionObject($this->collection);
$property = $reflection->getProperty('maxRetries');
$property->setAccessible(true);
$this->assertEquals(5, $property->getValue($this->collection));
}

public function testCount()
{
$result = $this->collection->count();
Expand Down

0 comments on commit df59e7b

Please sign in to comment.