Repository navigation
Adds transaction support - #58
WyriHaximus wants to merge 8 commits into
Conversation
f45996a to
9bfd1e1
Compare
5a949b0 to
7397828
Compare
4e9015d to
56b6868
Compare
56b6868 to
8b3ae9d
Compare
8b3ae9d to
61c9b9f
Compare
This PR adds support for transactions by reserving a single connection for a transaction. While keeping connection sharing for other queries on non-reserved connections.
It must be noted that when all connections are in use by transactions, all other queries and new transactions have to wait in the queue until a connection becomes available. This could lead to delays in the starting of queries and is a major change in the behaviour of this package. Follow-up work is in place to see if a single connection can handle multiple transactions. But that is out of scope for this PR.
To achieve the above, the following changes have been made to this package:
* Changed `ubuntu-latest` to `ubuntu-24.04` because `ikalnytskyi/action-setup-postgres@v7` errors with `sudo: 'apt-key': command not found`
* Fixed two deprecations: implicitly nullable types in `Client`, `Connection`, `ErrorException`, and `TestCase`
* Introduced a new class `ConnectionPool` to handle all connection pooling and reservations, and moved all the code related to that out of `Client`
* Added `transaction`, including an example in `example/` to start a transaction and give the user a `Transaction` to run their queries inside that transaction and `commit` or `rollback` in the end
* Hardened `Connection` against connection issues, ensuring those are handled correctly
* `Integration/TestCase` added cleanup in the setup method so the new transaction integration tests don't mess up the other integration tests
## Example
```php
$client->transaction()->flatMap(function (PgAsync\Transaction $tx) {
return $tx->executeStatement('INSERT INTO channel(name) VALUES ($1)', ['example'])
->concat($tx->query('SELECT COUNT(*) AS c FROM channel'))
->concat($tx->commit());
})->subscribe(
function () {
echo "Committed.\n";
},
function ($e) {
echo "Failed: " . $e->getMessage() . "\n";
}
);
```
61c9b9f to
c5b0338
Compare
|
@mbonneau This is now ready for review |
createConnection() adds every connection to the pool, including those that are reserved for a transaction and not ready yet. The cap check subtracted the pending reservations from that count, so while connections were being established each waiting transaction saw room under max_connections and opened another one. A burst of transactions therefore grew the pool far past the cap. Compare the plain connection count with the cap, in both the query path and the transaction waiter path. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Thanks for this, we are building on
Items 2 and 3 are fixed in WyriHaximus-labs#2 waiters are removed on dispose, and a failed Smaller things I did not change: |
Count connections that are still connecting against the pool cap
transaction($work) commits when the work completes, rolls back and rethrows the original error when it fails, and rolls back when the subscriber unsubscribes. beginTransaction() is the manual form the README documents. A waiter that unsubscribes while queued for a connection is removed from the queue, and a connection handed to a waiter that is already gone is released. A COMMIT/ROLLBACK that fails no longer keeps the connection reserved. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Release the connection after a failed COMMIT, and drop unsubscribed waiters
This PR adds support for transactions by reserving a single connection for a transaction. While keeping connection sharing for other queries on non-reserved connections.
It must be noted that when all connections are in use by transactions, all other queries and new transactions have to wait in the queue until a connection becomes available. This could lead to delays in the starting of queries and is a major change in the behaviour of this package. Follow-up work is in place to see if a single connection can handle multiple transactions. But that is out of scope for this PR.
To achieve the above, the following changes have been made to this package:
ubuntu-latesttoubuntu-24.04becauseikalnytskyi/action-setup-postgres@v7errors withsudo: 'apt-key': command not foundClient,Connection,ErrorException, andTestCaseConnectionPoolto handle all connection pooling and reservations, and moved all the code related to that out ofClienttransaction, including an example inexample/to start a transaction and give the user aTransactionto run their queries inside that transaction andcommitorrollbackin the endConnectionagainst connection issues, ensuring those are handled correctlyIntegration/TestCaseadded cleanup in the setup method so the new transaction integration tests don't mess up the other integration testsExample