|
24 | 24 | use Doctrine\DBAL\Result; |
25 | 25 | use Doctrine\DBAL\Schema\Schema; |
26 | 26 | use Doctrine\DBAL\Statement; |
| 27 | +use OC\DB\Middleware\ConnectionActivityNotifier; |
27 | 28 | use OC\DB\QueryBuilder\Partitioned\PartitionedQueryBuilder; |
28 | 29 | use OC\DB\QueryBuilder\Partitioned\PartitionSplit; |
29 | 30 | use OC\DB\QueryBuilder\QueryBuilder; |
@@ -132,6 +133,10 @@ public function __construct( |
132 | 133 | parent::__construct($params, $driver, $config, $eventManager); |
133 | 134 | $this->adapter = new $params['adapter']($this); |
134 | 135 | $this->tablePrefix = $params['tablePrefix']; |
| 136 | + $activityNotifier = $params['activity_notifier'] ?? null; |
| 137 | + if ($activityNotifier instanceof ConnectionActivityNotifier) { |
| 138 | + $activityNotifier->setListener($this->refreshLastConnectionCheck(...)); |
| 139 | + } |
135 | 140 | $this->isShardingEnabled = isset($this->params['sharding']) && !empty($this->params['sharding']); |
136 | 141 |
|
137 | 142 | if ($this->isShardingEnabled) { |
@@ -230,7 +235,7 @@ public function connect($connectionName = null) { |
230 | 235 | $status = parent::connect(); |
231 | 236 | $eventLogger->end('connect:db'); |
232 | 237 |
|
233 | | - $this->lastConnectionCheck[$this->getConnectionName()] = time(); |
| 238 | + $this->refreshLastConnectionCheck(); |
234 | 239 |
|
235 | 240 | return $status; |
236 | 241 | } catch (Exception $e) { |
@@ -896,21 +901,32 @@ public function rollBack() { |
896 | 901 | private function reconnectIfNeeded(): void { |
897 | 902 | if ( |
898 | 903 | !isset($this->lastConnectionCheck[$this->getConnectionName()]) |
899 | | - || time() <= $this->lastConnectionCheck[$this->getConnectionName()] + 30 |
| 904 | + || time() <= $this->lastConnectionCheck[$this->getConnectionName()] + self::CONNECTION_CHECK_INTERVAL |
900 | 905 | || $this->isTransactionActive() |
901 | 906 | ) { |
902 | 907 | return; |
903 | 908 | } |
904 | 909 |
|
905 | 910 | try { |
906 | 911 | $this->_conn->query($this->getDriver()->getDatabasePlatform()->getDummySelectSQL()); |
907 | | - $this->lastConnectionCheck[$this->getConnectionName()] = time(); |
| 912 | + $this->refreshLastConnectionCheck(); |
908 | 913 | } catch (ConnectionLost|\Exception $e) { |
909 | 914 | $this->logger->warning('Exception during connectivity check, closing and reconnecting', ['exception' => $e]); |
910 | 915 | $this->close(); |
911 | 916 | } |
912 | 917 | } |
913 | 918 |
|
| 919 | + /** |
| 920 | + * A successful round trip proves the connection is alive: pushing the idle |
| 921 | + * timer forward keeps the connectivity probe of reconnectIfNeeded() from |
| 922 | + * firing between adjacent operations, where its query would reset the |
| 923 | + * driver level last insert id on MySQL. Invoked for every driver level |
| 924 | + * execution via the ConnectionActivityMiddleware. |
| 925 | + */ |
| 926 | + private function refreshLastConnectionCheck(): void { |
| 927 | + $this->lastConnectionCheck[$this->getConnectionName()] = time(); |
| 928 | + } |
| 929 | + |
914 | 930 | private function getConnectionName(): string { |
915 | 931 | return $this->isConnectedToPrimary() ? 'primary' : 'replica'; |
916 | 932 | } |
|
0 commit comments