diff --git a/CHANGELOG.md b/CHANGELOG.md index 37cc8e97..d3268bd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ -# v7.2.0 (Not released yet) +# v7.3.0 (2024-04-17) + +Added +- Request and Transaction tagging support (#206) + +# v7.2.0 (2024-03-27) Added - Support for `Query\Builder::upsert()` (#203) diff --git a/README.md b/README.md index 2d4b1d22..a7ea3be6 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,19 @@ $queryBuilder > This creates a new session in the background which is not shared with the current session pool. > This means, queries running with data boost will not be associated with transactions that may be taking place. +### Request Tags and Transaction Tags + +Spanner allows you to attach tags to your queries and transactions that can be [used for troubleshooting](https://cloud.google.com/spanner/docs/introspection/troubleshooting-with-tags). + +You can set request tags and transaction tags as below. + +```php +$requestPath = request()->path(); +$tag = 'url=' . $requestPath; +$connection->setRequestTag($tag); +$connection->setTransactionTag($tag); +``` + ### Data Types Some data types of Google Cloud Spanner does not have corresponding built-in type of PHP. diff --git a/phpstan.neon b/phpstan.neon index e0d4e541..325089c4 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -44,3 +44,6 @@ parameters: - message: "#^Expression on left side of \\?\\? is not nullable\\.$#" count: 1 path: src/Connection.php + - message: "#^Cannot access offset 'requestTag' on mixed\\.$#" + count: 1 + path: src/Connection.php diff --git a/src/Concerns/ManagesTagging.php b/src/Concerns/ManagesTagging.php new file mode 100644 index 00000000..efe4de56 --- /dev/null +++ b/src/Concerns/ManagesTagging.php @@ -0,0 +1,67 @@ +requestTag = $tag; + return $this; + } + + /** + * @return string|null + */ + public function getRequestTag(): ?string + { + return $this->requestTag; + } + + /** + * @param string|null $tag + * @return $this + */ + public function setTransactionTag(?string $tag): static + { + $this->transactionTag = $tag; + return $this; + } + + /** + * @return string|null + */ + public function getTransactionTag(): ?string + { + return $this->transactionTag; + } +} diff --git a/src/Concerns/ManagesTransactions.php b/src/Concerns/ManagesTransactions.php index 2e000a97..fe47ca21 100644 --- a/src/Concerns/ManagesTransactions.php +++ b/src/Concerns/ManagesTransactions.php @@ -59,7 +59,14 @@ public function transaction(Closure $callback, $attempts = -1) return parent::transaction($callback, $attempts); } - return $this->withSessionNotFoundHandling(function () use ($callback, $attempts) { + $options = ['maxRetries' => $attempts - 1]; + + $tag = $this->getTransactionTag(); + if ($tag !== null) { + $options['tag'] = $tag; + } + + return $this->withSessionNotFoundHandling(function () use ($callback, $options) { $return = $this->getSpannerDatabase()->runTransaction(function (Transaction $tx) use ($callback) { try { $this->currentTransaction = $tx; @@ -81,7 +88,7 @@ public function transaction(Closure $callback, $attempts = -1) $this->rollBack(); throw $e; } - }, ['maxRetries' => $attempts - 1]); + }, $options); $this->fireConnectionEvent('committed'); diff --git a/src/Connection.php b/src/Connection.php index 4a1f115a..e14e27cf 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -52,6 +52,7 @@ class Connection extends BaseConnection Concerns\ManagesMutations, Concerns\ManagesPartitionedDml, Concerns\ManagesSessionPool, + Concerns\ManagesTagging, Concerns\ManagesTransactions, Concerns\MarksAsNotSupported; @@ -571,9 +572,16 @@ protected function executeQuery(string $query, array $bindings, array $options): return $this->executePartitionedQuery($query, $options); } - return $this->getDatabaseContext() - ->execute($query, $options) - ->rows(); + $tag = $this->getRequestTag(); + if ($tag !== null) { + $options['requestOptions'] ??= []; + $options['requestOptions']['requestTag'] = $tag; + } + + if ($transaction = $this->getCurrentTransaction()) { + return $transaction->execute($query, $options)->rows(); + } + return $this->getSpannerDatabase()->execute($query, $options)->rows(); } /** diff --git a/tests/Concerns/ManagesTagsTest.php b/tests/Concerns/ManagesTagsTest.php new file mode 100644 index 00000000..cc4bfa15 --- /dev/null +++ b/tests/Concerns/ManagesTagsTest.php @@ -0,0 +1,44 @@ +getConnection(); + assert($conn instanceof Connection); + $conn->setRequestTag('url=/api/users'); + $this->assertSame('url=/api/users', $conn->getRequestTag()); + $conn->setRequestTag(null); + $this->assertNull($conn->getRequestTag()); + } + + public function test_set_and_get_transactionTag(): void + { + $conn = $this->getDefaultConnection(); + assert($conn instanceof Connection); + $conn->setTransactionTag('url=/api/users/update'); + $this->assertSame('url=/api/users/update', $conn->getTransactionTag()); + $conn->setTransactionTag(null); + $this->assertNull($conn->getTransactionTag()); + } +}