private function runTransactionWithRetry(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 commitWithRetry(\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 updateEmployeeInfo(\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->commitWithRetry($session);
}

private function doUpdateEmployeeInfo(\MongoDB\Client $client)
{
    // Start a session.
    $session = $client->startSession();

    try {
        $this->runTransactionWithRetry([$this, 'updateEmployeeInfo'], $client, $session);
    } catch (\MongoDB\Driver\Exception\Exception $error) {
        // Do something with error
    }
}