-
-
Notifications
You must be signed in to change notification settings - Fork 505
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Only retry transaction once #2604
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -115,6 +115,50 @@ public function testTransientInsertError(): void | |
self::assertEquals([], $this->uow->getDocumentChangeSet($friendUser)); | ||
} | ||
|
||
public function testMultipleTransientErrors(): void | ||
{ | ||
$firstUser = new ForumUser(); | ||
$firstUser->username = 'alcaeus'; | ||
$this->uow->persist($firstUser); | ||
|
||
$secondUser = new ForumUser(); | ||
$secondUser->username = 'jmikola'; | ||
$this->uow->persist($secondUser); | ||
|
||
$friendUser = new FriendUser('GromNaN'); | ||
$this->uow->persist($friendUser); | ||
|
||
// Add a failpoint that triggers multiple transient errors. The transaction is expected to fail | ||
$this->createTransientFailPoint('insert', 2); | ||
|
||
try { | ||
$this->uow->commit(); | ||
self::fail('Expected exception when committing'); | ||
} catch (Throwable $e) { | ||
self::assertInstanceOf(BulkWriteException::class, $e); | ||
self::assertSame(192, $e->getCode()); | ||
} | ||
|
||
self::assertSame( | ||
0, | ||
$this->dm->getDocumentCollection(ForumUser::class)->countDocuments(), | ||
); | ||
|
||
self::assertSame( | ||
0, | ||
$this->dm->getDocumentCollection(FriendUser::class)->countDocuments(), | ||
); | ||
|
||
self::assertTrue($this->uow->isScheduledForInsert($firstUser)); | ||
self::assertNotEquals([], $this->uow->getDocumentChangeSet($firstUser)); | ||
|
||
self::assertTrue($this->uow->isScheduledForInsert($secondUser)); | ||
self::assertNotEquals([], $this->uow->getDocumentChangeSet($secondUser)); | ||
|
||
self::assertTrue($this->uow->isScheduledForInsert($friendUser)); | ||
self::assertNotEquals([], $this->uow->getDocumentChangeSet($friendUser)); | ||
} | ||
|
||
public function testDuplicateKeyError(): void | ||
{ | ||
// Create a unique index on the collection to let the second insert fail | ||
|
@@ -534,12 +578,11 @@ protected static function getConfiguration(): Configuration | |
return $configuration; | ||
} | ||
|
||
private function createTransientFailPoint(string $failCommand): void | ||
private function createTransientFailPoint(string $failCommand, int $times = 1): void | ||
{ | ||
$this->dm->getClient()->selectDatabase('admin')->command([ | ||
'configureFailPoint' => 'failCommand', | ||
// Trigger the error twice, working around retryable writes | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While testing this change, I noticed that with a single retry all other tests started failing. Upon further investigation, it turns out that using an additional failure to account for retryable writes isn't necessary. Quoting from the Retryable Writes Documentation:
With that in mind, we don't need to account for this and a single failure is sufficient for this fail point (except for the one test where we want multiple failures to specifically test that the operation is only retried once). |
||
'mode' => ['times' => 2], | ||
'mode' => ['times' => $times], | ||
'data' => [ | ||
'errorCode' => 192, // FailPointEnabled | ||
'errorLabels' => ['TransientTransactionError'], | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what the best course of action is here, but since the code in question comes from the apache-2.0-licensed MongoDB library and the ODM is MIT licensed, we do need some kind of license and copyright information. Let me know your thoughts on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's OK but I'm not a lawyer :) Maybe you could ask internally if it's sufficient?