Pass CommandInterface to retry handler (fixes #1155, #1130)#1171
Pass CommandInterface to retry handler (fixes #1155, #1130)#1171bautrukevich wants to merge 3 commits intoyiisoft:masterfrom
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1171 +/- ##
============================================
- Coverage 98.62% 98.39% -0.23%
- Complexity 1645 1655 +10
============================================
Files 120 120
Lines 4292 4312 +20
============================================
+ Hits 4233 4243 +10
- Misses 59 69 +10 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Updates the command retry mechanism to provide more context to retry handlers by passing the executing command instance, enabling smarter retry logic (e.g., recreating statements / inspecting params), as requested in #1155 and #1130.
Changes:
- Pass
CommandInterface($this) as a third argument to the retry handler callback in PDO command execution. - Update
CommandInterface::setRetryHandler()docblock to document the new handler signature and attempt indexing. - Add/expand
AbstractCommand::setRetryHandler()docblock to reflect the new handler signature.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
src/Driver/Pdo/AbstractPdoCommand.php |
Passes the executing command instance into the retry handler during internalExecute(). |
src/Command/CommandInterface.php |
Updates retry-handler docblock/signature description to include CommandInterface parameter and attempt semantics. |
src/Command/AbstractCommand.php |
Adds a matching retry-handler docblock on the concrete setRetryHandler() implementation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if ($this->retryHandler === null || !($this->retryHandler)($e, $attempt, $this)) { | ||
| throw $e; | ||
| } |
There was a problem hiding this comment.
This change calls the retry handler with 3 arguments. There are existing in-repo handlers that still accept only 2 parameters (e.g. tests/Common/CommonCommandTest.php), which will now throw an ArgumentCountError at runtime. Please update all internal usages/tests/docs accordingly, or consider a backward-compatible invocation strategy (e.g. detect handler arity and pass only the supported number of args).
| if ($this->retryHandler === null || !($this->retryHandler)($e, $attempt, $this)) { | |
| throw $e; | |
| } | |
| $handler = $this->retryHandler; | |
| if ($handler === null) { | |
| throw $e; | |
| } | |
| $callable = \Closure::fromCallable($handler); | |
| $reflection = new \ReflectionFunction($callable); | |
| $paramCount = $reflection->getNumberOfParameters(); | |
| if ($paramCount >= 3) { | |
| $shouldRetry = $callable($e, $attempt, $this); | |
| } elseif ($paramCount === 2) { | |
| $shouldRetry = $callable($e, $attempt); | |
| } elseif ($paramCount === 1) { | |
| $shouldRetry = $callable($e); | |
| } else { | |
| $shouldRetry = $callable(); | |
| } | |
| if (!$shouldRetry) { | |
| throw $e; | |
| } |
| * to execute the command, starting from `1`. | ||
| * The closure will receive an {@see Exception} converted from the thrown database exception, | ||
| * the current attempt to execute the command (starting from `0`), and the {@see CommandInterface} | ||
| * instance to allow access to connection and parameters for reconnection logic. |
There was a problem hiding this comment.
The doc says the retry handler can use the passed CommandInterface to access the connection for reconnection logic, but CommandInterface doesn’t expose the underlying ConnectionInterface (no getDb()/getConnection() method). Either adjust the docs to reflect what is actually accessible, or extend the API (e.g. add a connection accessor or pass ConnectionInterface as an argument) so reconnection logic is truly possible.
| * instance to allow access to connection and parameters for reconnection logic. | |
| * instance to allow access to the command and its parameters for custom retry logic. |
| } | ||
|
|
||
| /** | ||
| * Sets a closure (anonymous function) which called when a database exception is thrown when executing the command. |
There was a problem hiding this comment.
Docblock grammar: “Sets a closure ... which called” is ungrammatical; please change to “which is called” / “that is called”.
| * Sets a closure (anonymous function) which called when a database exception is thrown when executing the command. | |
| * Sets a closure (anonymous function) which is called when a database exception is thrown when executing the command. |
| * | ||
| * The closure will receive an {@see Exception} converted from the thrown database exception, | ||
| * the current attempt to execute the command (starting from `0`), and the {@see CommandInterface} | ||
| * instance to allow access to connection and parameters. |
There was a problem hiding this comment.
This doc states the passed CommandInterface allows access to the connection, but CommandInterface doesn’t provide any public accessor to the underlying ConnectionInterface. Either remove/adjust this wording, or add an explicit API to access the connection so retry handlers can actually implement reconnection logic as described.
| * instance to allow access to connection and parameters. | |
| * instance to allow access to the command's parameters and other state exposed by the interface. |
| $e = (new ConvertException($e, $rawSql))->run(); | ||
|
|
||
| if ($this->retryHandler === null || !($this->retryHandler)($e, $attempt)) { | ||
| // ✨ Pass $this (CommandInterface) to retry handler |
There was a problem hiding this comment.
The inline comment uses a decorative emoji ("✨"), which is inconsistent with typical source comments and can be noisy in diffs/blame. Consider removing it or rewriting as a plain, descriptive comment (or relying on the code being self-explanatory).
| // ✨ Pass $this (CommandInterface) to retry handler | |
| // Pass $this (CommandInterface) to the retry handler. |
…rst attempt and prevent unsafe reconnections during active transactions
Summary
Implements feature request #1155 and #1130.
Allows retry handlers to access CommandInterface to implement connection renewal logic.
Changes
CommandInterfaceas third parameter to retry handler callback(Exception, int): boolto(Exception, int, CommandInterface): boolBreaking Change
Yes - existing retry handlers need to be updated to accept the new parameter (can be ignored with
_).Usage Example
Migration Guide
Update existing retry handlers: