Skip to content

Commit

Permalink
Merge pull request #48 from xp-forge/feature/retried-error-msg
Browse files Browse the repository at this point in the history
Extend handling to include if a write was retried
  • Loading branch information
thekid authored Oct 14, 2024
2 parents 826c59d + 176008d commit 62329a7
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 10 deletions.
22 changes: 17 additions & 5 deletions src/main/php/com/mongodb/Error.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
class Error extends XPException {
const NOT_PRIMARY= [10107 => 1, 11602 => 1, 13435 => 1, 13436 => 1];

private $kind;
private $kind, $retried;

/**
* Creates a new error
Expand All @@ -20,21 +20,33 @@ class Error extends XPException {
* @param string $kind
* @param string $message
* @param ?lang.Throwable $cause
* @param int|bool $retried
*/
public function __construct($code, $kind, $message, $cause= null) {
parent::__construct($message, $cause);
public function __construct($code, $kind, $message, $cause= null, $retried= 0) {
parent::__construct($message.($retried ? " - retried {$retried} time(s)" : ''), $cause);
$this->code= $code;
$this->kind= $kind;
$this->retried= (int)$retried;
}

/** @return int */
public function retried() { return $this->retried; }

/**
* Creates an error from a given error document
*
* @param [:var] $document
* @param int|bool $retried
* @return self
*/
public static function newInstance($document) {
return new self($document['code'], $document['codeName'], $document['errmsg']);
public static function newInstance($document, $retried= 0) {
return new self(
$document['code'],
$document['codeName'],
$document['errmsg'],
null,
$retried
);
}

/** @return string */
Expand Down
2 changes: 1 addition & 1 deletion src/main/php/com/mongodb/io/Commands.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public function send($options, $sections) {
goto retry;
}

throw Error::newInstance($r['body']);
throw Error::newInstance($r['body'], !$this->retry);
} finally {
$this->retry= false;
}
Expand Down
7 changes: 4 additions & 3 deletions src/main/php/com/mongodb/io/Protocol.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ public function write(array $options, $sections) {
}

$rp= $sections['$readPreference'] ?? $this->readPreference;
$retry= 1;
$retry= true;

// Use send() API to prevent using exceptions for flow control
retry: $conn= $this->establish([$this->nodes['primary']], 'writing');
Expand All @@ -271,12 +271,13 @@ public function write(array $options, $sections) {
// Check for "NotWritablePrimary" error, which indicates our view of the cluster
// may be outdated, see https://github.com/xp-forge/mongodb/issues/43. Refresh
// view using the "hello" command, then retry the command once.
if ($retry-- && isset(Error::NOT_PRIMARY[$r['body']['code']])) {
if ($retry && isset(Error::NOT_PRIMARY[$r['body']['code']])) {
$this->useCluster($conn->hello());
$retry= false;
goto retry;
}

throw Error::newInstance($r['body']);
throw Error::newInstance($r['body'], !$retry);
}

/** @return void */
Expand Down
10 changes: 9 additions & 1 deletion src/test/php/com/mongodb/unittest/CollectionTest.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -406,12 +406,20 @@ public function not_writable_primary_retried($kind, $command) {
));
}

#[Test, Expect(class: Error::class, message: 'Second occurrence'), Values(from: 'writes')]
#[Test, Expect(class: Error::class, message: 'Second occurrence - retried 1 time(s)'), Values(from: 'writes')]
public function not_writable_primary_not_retried_more_than_once($kind, $command) {
$command($this->newFixture(
$this->error(10107, 'NotWritablePrimary', 'First occurrence'),
$this->hello(self::$PRIMARY),
$this->error(10107, 'NotWritablePrimary', 'Second occurrence')
));
}

#[Test, Expect(class: Error::class, message: 'Test message'), Values(from: 'writes')]
public function other_errors_not_retried($kind, $command) {
$command($this->newFixture(
$this->error(6100, 'FailedOnce', 'Test message'),
$this->error(6101, 'FailedAgain', 'The previous error should have thrown')
));
}
}

0 comments on commit 62329a7

Please sign in to comment.