ReconnectStrategy.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 3.6.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Database\Retry;
  16. use Cake\Core\Retry\RetryStrategyInterface;
  17. use Cake\Database\Connection;
  18. use Exception;
  19. /**
  20. * Makes sure the connection to the database is alive before authorizing
  21. * the retry of an action.
  22. *
  23. * @internal
  24. */
  25. class ReconnectStrategy implements RetryStrategyInterface
  26. {
  27. /**
  28. * The list of error strings to match when looking for a disconnection error.
  29. *
  30. * This is a static variable to enable opcache to inline the values.
  31. *
  32. * @var array
  33. */
  34. protected static $causes = [
  35. 'gone away',
  36. 'Lost connection',
  37. 'Transaction() on null',
  38. 'closed the connection unexpectedly',
  39. 'closed unexpectedly',
  40. 'deadlock avoided',
  41. 'decryption failed or bad record mac',
  42. 'is dead or not enabled',
  43. 'no connection to the server',
  44. 'query_wait_timeout',
  45. 'reset by peer',
  46. 'terminate due to client_idle_limit',
  47. 'while sending',
  48. 'writing data to the connection',
  49. ];
  50. /**
  51. * The connection to check for validity
  52. *
  53. * @var Connection
  54. */
  55. protected $connection;
  56. /**
  57. * Creates the ReconnectStrategy object by storing a reference to the
  58. * passed connection. This reference will be used to automatically
  59. * reconnect to the server in case of failure.
  60. *
  61. * @param \Cake\Database\Connection $connection The connection to check
  62. */
  63. public function __construct(Connection $connection)
  64. {
  65. $this->connection = $connection;
  66. }
  67. /**
  68. * Checks whether or not the exception was caused by a lost connection,
  69. * and returns true if it was able to successfully reconnect.
  70. *
  71. * @param Exception $exception The exception to check for its message
  72. * @param int $retryCount The number of times the action has been already called
  73. * @return bool Whether or not it is OK to retry the action
  74. */
  75. public function shouldRetry(Exception $exception, $retryCount)
  76. {
  77. $message = $exception->getMessage();
  78. foreach (static::$causes as $cause) {
  79. if (strstr($message, $cause) !== false) {
  80. return $this->reconnect();
  81. }
  82. }
  83. return false;
  84. }
  85. /**
  86. * Tries to re-establish the connection to the server, if it is safe to do so
  87. *
  88. * @return bool Whether or not the connection was re-established
  89. */
  90. protected function reconnect()
  91. {
  92. if ($this->connection->inTransaction()) {
  93. // It is not safe to blindly reconnect in the middle of a transaction
  94. return false;
  95. }
  96. try {
  97. // Make sure we free any resources associated with the old connection
  98. $this->connection->disconnect();
  99. } catch (Exception $e) {
  100. }
  101. try {
  102. $this->connection->connect();
  103. $this->connection->log('[RECONNECT]');
  104. return true;
  105. } catch (Exception $e) {
  106. // If there was an error connecting again, don't report it back,
  107. // let the retry handler do it.
  108. return false;
  109. }
  110. }
  111. }