Commit 1f1da783 authored by Derick Rethans's avatar Derick Rethans

PHPLIB-350: Provide Transactions example for Docs

parent 1e2e6b3d
......@@ -2,6 +2,7 @@
namespace MongoDB\Tests;
use MongoDB\Client;
use MongoDB\Database;
use MongoDB\Driver\Cursor;
use MongoDB\Driver\Server;
......@@ -1180,6 +1181,245 @@ class DocumentationExamplesTest extends FunctionalTestCase
$this->assertEquals('cuisine_1_name_1', $indexName);
}
// Start Transactions Intro Example 1
private function updateEmployeeInfo1(\MongoDB\Client $client, \MongoDB\Driver\Session $session)
{
$session->startTransaction([
'readConcern' => new \MongoDB\Driver\ReadConcern('snapshot'),
'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY)
]);
try {
$client->hr->employees->updateOne(
['employee' => 3],
['$set' => ['status' => 'Inactive']],
['session' => $session]
);
$client->reporting->events->insertOne(
['employee' => 3, 'status' => [ 'new' => 'Inactive', 'old' => 'Active']],
['session' => $session]
);
} catch (\MongoDB\Driver\Exception\Exception $error) {
echo "Caught exception during transaction, aborting.\n";
$session->abortTransaction();
throw $error;
}
while (true) {
try {
$session->commitTransaction();
echo "Transaction committed.\n";
break;
} catch (\MongoDB\Driver\Exception\CommandException $error) {
$resultDoc = $error->getResultDocument();
if (isset($resultDoc->errorLabels) && in_array('UnknownTransactionCommitResult', $resultDoc->errorLabels)) {
echo "UnknownTransactionCommitResult, retrying commit operation ...\n";
continue;
} else {
echo "Error during commit ...\n";
throw $error;
}
} catch (\MongoDB\Driver\Exception\Exception $error) {
echo "Error during commit ...\n";
throw $error;
}
}
}
// End Transactions Intro Example 1
public function testTransactions_intro_example_1()
{
if ($this->getPrimaryServer()->getType() === Server::TYPE_STANDALONE) {
$this->markTestSkipped('Transactions are not supported on standalone servers');
}
if (version_compare($this->getFeatureCompatibilityVersion(), '4.0', '<')) {
$this->markTestSkipped('Transactions are only supported on FCV 4.0 or higher');
}
$client = new Client($this->getUri());
/* The WC is required: https://docs.mongodb.com/manual/core/transactions/#transactions-and-locks */
$client->hr->dropCollection('employees', ['writeConcern' => new \MongoDB\Driver\WriteConcern('majority')]);
$client->reporting->dropCollection('events', ['writeConcern' => new \MongoDB\Driver\WriteConcern('majority')]);
/* Collections need to be created before a transaction starts */
$client->hr->createCollection('employees', ['writeConcern' => new \MongoDB\Driver\WriteConcern('majority')]);
$client->reporting->createCollection('events', ['writeConcern' => new \MongoDB\Driver\WriteConcern('majority')]);
$session = $client->startSession();
ob_start();
try {
$this->updateEmployeeInfo1($client, $session);
} finally {
ob_end_clean();
}
}
// Start Transactions Retry Example 1
private function runTransactionWithRetry1(callable $txnFunc, \MongoDB\Client $client, \MongoDB\Driver\Session $session)
{
while (true) {
try {
$txnFunc($client, $session); // performs transaction
break;
} catch (\MongoDB\Driver\Exception\CommandException $error) {
$resultDoc = $error->getResultDocument();
echo "Transaction aborted. Caught exception during transaction.\n";
// If transient error, retry the whole transaction
if (isset($resultDoc->errorLabels) && in_array('TransientTransactionError', $resultDoc->errorLabels)) {
echo "TransientTransactionError, retrying transaction ...\n";
continue;
} else {
throw $error;
}
} catch (\MongoDB\Driver\Exception\Exception $error) {
throw $error;
}
}
}
// End Transactions Retry Example 1
// Start Transactions Retry Example 2
private function commitWithRetry2(\MongoDB\Driver\Session $session)
{
while (true) {
try {
$session->commitTransaction();
echo "Transaction committed.\n";
break;
} catch (\MongoDB\Driver\Exception\CommandException $error) {
$resultDoc = $error->getResultDocument();
if (isset($resultDoc->errorLabels) && in_array('UnknownTransactionCommitResult', $resultDoc->errorLabels)) {
echo "UnknownTransactionCommitResult, retrying commit operation ...\n";
continue;
} else {
echo "Error during commit ...\n";
throw $error;
}
} catch (\MongoDB\Driver\Exception\Exception $error) {
echo "Error during commit ...\n";
throw $error;
}
}
}
// End Transactions Retry Example 2
// Start Transactions Retry Example 3
private function runTransactionWithRetry3(callable $txnFunc, \MongoDB\Client $client, \MongoDB\Driver\Session $session)
{
while (true) {
try {
$txnFunc($client, $session); // performs transaction
break;
} catch (\MongoDB\Driver\Exception\CommandException $error) {
$resultDoc = $error->getResultDocument();
// If transient error, retry the whole transaction
if (isset($resultDoc->errorLabels) && in_array('TransientTransactionError', $resultDoc->errorLabels)) {
continue;
} else {
throw $error;
}
} catch (\MongoDB\Driver\Exception\Exception $error) {
throw $error;
}
}
}
private function commitWithRetry3(\MongoDB\Driver\Session $session)
{
while (true) {
try {
$session->commitTransaction();
echo "Transaction committed.\n";
break;
} catch (\MongoDB\Driver\Exception\CommandException $error) {
$resultDoc = $error->getResultDocument();
if (isset($resultDoc->errorLabels) && in_array('UnknownTransactionCommitResult', $resultDoc->errorLabels)) {
echo "UnknownTransactionCommitResult, retrying commit operation ...\n";
continue;
} else {
echo "Error during commit ...\n";
throw $error;
}
} catch (\MongoDB\Driver\Exception\Exception $error) {
echo "Error during commit ...\n";
throw $error;
}
}
}
private function updateEmployeeInfo3(\MongoDB\Client $client, \MongoDB\Driver\Session $session)
{
$session->startTransaction([
'readConcern' => new \MongoDB\Driver\ReadConcern("snapshot"),
'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY)
]);
try {
$client->hr->employees->updateOne(
['employee' => 3],
['$set' => ['status' => 'Inactive']],
['session' => $session]
);
$client->reporting->events->insertOne(
['employee' => 3, 'status' => [ 'new' => 'Inactive', 'old' => 'Active']],
['session' => $session]
);
} catch (\MongoDB\Driver\Exception\Exception $error) {
echo "Caught exception during transaction, aborting.\n";
$session->abortTransaction();
throw $error;
}
$this->commitWithRetry3($session);
}
private function doUpdateEmployeeInfo(\MongoDB\Client $client)
{
// Start a session.
$session = $client->startSession();
try {
$this->runTransactionWithRetry3([$this, 'updateEmployeeInfo3'], $client, $session);
} catch (\MongoDB\Driver\Exception\Exception $error) {
// Do something with error
}
}
// End Transactions Retry Example 3
public function testTransactions_retry_example_3()
{
if ($this->getPrimaryServer()->getType() === Server::TYPE_STANDALONE) {
$this->markTestSkipped('Transactions are not supported on standalone servers');
}
if (version_compare($this->getFeatureCompatibilityVersion(), '4.0', '<')) {
$this->markTestSkipped('Transactions are only supported on FCV 4.0 or higher');
}
$client = new Client($this->getUri());
/* The WC is required: https://docs.mongodb.com/manual/core/transactions/#transactions-and-locks */
$client->hr->dropCollection('employees', ['writeConcern' => new \MongoDB\Driver\WriteConcern('majority')]);
$client->reporting->dropCollection('events', ['writeConcern' => new \MongoDB\Driver\WriteConcern('majority')]);
/* Collections need to be created before a transaction starts */
$client->hr->createCollection('employees', ['writeConcern' => new \MongoDB\Driver\WriteConcern('majority')]);
$client->reporting->createCollection('events', ['writeConcern' => new \MongoDB\Driver\WriteConcern('majority')]);
ob_start();
try {
$this->doUpdateEmployeeInfo($client);
} finally {
ob_end_clean();
}
}
/**
* Return the test collection name.
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment