You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Improve the shutdown sequence by separating a dead child pid (not running anymore) from a running child pid.
Description
When shutting down Selenium::WebDriver::ServiceManager#stop_server issues a /shutdown request against the webdriver server and the server exits cleanly, however the mechanism to assert if the child process is up or not cannot distinguish between busy or not found.
Selenium::WebDriver::ChildProcess#exited? returns false when the process is still alive because Selenium::WebDriver::ChildProcess#waitpid2 returns nil.
However, by catching Errno::ECHILD and Errno::ESRCH and returning nil#waitpid2 masks a not running pid as "running" delaying the shutdown procedure when the server was already gone.
This patch moves the exception handling away from the Process wrappers so its closer to the decision points in Selenium::WebDriver::ChildProcess#exited? and Selenium::WebDriver::ChildProcess#stop.
Addresses a similar problem as in #14032. With this patch the shutdown sequence looks like:
Send a /shutdown signal to the server [if supported]
Check for the server pid
If it cannot be found (Errno::ECHILD, Errno::ESRCH), then assume the server has shutdown.
else: wait and retry in ~100 ms.
repeat for 20 seconds (Selenium::WebDriver::ServiceManager::STOP_TIMEOUT).
Try to send a TERM signal to the server.
Check for the server pid
If it cannot be found (Errno::ECHILD, Errno::ESRCH), then assume the server has shutdown.
else: wait and retry in ~100 ms.
repeat for 3 seconds (default value of timeout inSelenium::WebDriver::ChildProcess#stop ).
Try to send a KILL signal to the server.
Check for the server pid
If it cannot be found (Errno::ECHILD, Errno::ESRCH), then assume the server has shutdown.
else: wait and retry in ~100 ms.
Motivation and Context
Noticed that the tests will end, but it'll be hung for 10~20 seconds doing nothing. This patch reduces my test run time from ~32s to ~13s consistently.
Types of changes
Bug fix (non-breaking change which fixes an issue)
New feature (non-breaking change which adds functionality)
Breaking change (fix or feature that would cause existing functionality to change)
When shutting down `Selenium::WebDriver::ServiceManager#stop_server`
issues a `/shutdown` request against the webdriver server and the
server exits cleanly, however the mechanism to assert if the child
process is up or not cannot distinguish between busy or not found.
`Selenium::WebDriver::ChildProcess#exited?` returns `false` when the
process is still alive because
`Selenium::WebDriver::ChildProcess#waitpid2` returns `nil`.
However, by catching `Errno::ECHILD` and `Errno::ESRCH` and returning
`nil` `#waitpid2` masks a not running pid as "running" delaying the
shutdown procedure when the server was already gone.
This patch moves the exception handling away from the `Process` wrappers
so its closer to the decision points in
`Selenium::WebDriver::ChildProcess#exited?` and
`Selenium::WebDriver::ChildProcess#stop`.
Addresses a similar inconsistency in SeleniumHQ#14032
Error Handling The new error handling in the stop method might mask other potential errors. Consider adding a more specific rescue clause or logging the error details.
Code Duplication The terminate_and_wait_else_kill method contains logic that was previously in the stop method. Consider if this abstraction is necessary or if it adds unnecessary complexity.
Add error handling for the server shutdown HTTP request
In the stop_server method, consider adding error handling for the HTTP request. This can help manage potential network issues or server errors during shutdown.
def stop_server
connect_to_server do |http|
headers = WebDriver::Remote::Http::Common::DEFAULT_HEADERS.dup
WebDriver.logger.debug("Sending shutdown request to server", id: :driver_service)
- http.get('/shutdown', headers)+ begin+ http.get('/shutdown', headers)+ rescue StandardError => e+ WebDriver.logger.warn("Error during server shutdown: #{e.message}", id: :driver_service)+ end
end
end
Apply this suggestion
Suggestion importance[1-10]: 8
Why: Implementing error handling for the HTTP request in stop_server is a significant improvement as it addresses potential network issues or server errors, enhancing the robustness of the code.
8
Enhancement
Enhance error logging by including the specific exception type
In the exited? method, consider logging the specific exception type when catching Errno::ECHILD or Errno::ESRCH. This can provide more detailed debugging information.
Why: Adding the specific exception type to the log message enhances debugging and provides more context, which is beneficial for maintenance and troubleshooting.
7
Improve method name to better reflect its functionality
Consider using a more descriptive method name for terminate_and_wait_else_kill. A name like graceful_shutdown_with_fallback might better convey the method's behavior.
-def terminate_and_wait_else_kill(timeout)+def graceful_shutdown_with_fallback(timeout)
WebDriver.logger.debug("Sending TERM to process: #{@pid}", id: :process)
terminate(@pid)
poll_for_exit(timeout)
WebDriver.logger.debug(" -> stopped #{@pid}", id: :process)
rescue TimeoutError, Errno::EINVAL
WebDriver.logger.debug(" -> sending KILL to process: #{@pid}", id: :process)
kill(@pid)
wait
WebDriver.logger.debug(" -> killed #{@pid}", id: :process)
end
Apply this suggestion
Suggestion importance[1-10]: 6
Why: The suggestion to rename the method to graceful_shutdown_with_fallback improves code readability and better describes the method's functionality, but it is not crucial for functionality.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
User description
Improve the shutdown sequence by separating a dead child pid (not running anymore) from a running child pid.
Description
When shutting down
Selenium::WebDriver::ServiceManager#stop_server
issues a/shutdown
request against the webdriver server and the server exits cleanly, however the mechanism to assert if the child process is up or not cannot distinguish between busy or not found.Selenium::WebDriver::ChildProcess#exited?
returnsfalse
when the process is still alive becauseSelenium::WebDriver::ChildProcess#waitpid2
returnsnil
.However, by catching
Errno::ECHILD
andErrno::ESRCH
and returningnil
#waitpid2
masks a not running pid as "running" delaying the shutdown procedure when the server was already gone.This patch moves the exception handling away from the
Process
wrappers so its closer to the decision points inSelenium::WebDriver::ChildProcess#exited?
andSelenium::WebDriver::ChildProcess#stop
.Addresses a similar problem as in #14032. With this patch the shutdown sequence looks like:
/shutdown
signal to the server [if supported]Selenium::WebDriver::ServiceManager::STOP_TIMEOUT
).TERM
signal to the server.timeout
inSelenium::WebDriver::ChildProcess#stop
).KILL
signal to the server.Motivation and Context
Noticed that the tests will end, but it'll be hung for 10~20 seconds doing nothing. This patch reduces my test run time from ~32s to ~13s consistently.
Types of changes
Checklist
Logs of a production application
with selenium-webdrivers 4.23.0
with this patch:
PR Type
enhancement, tests
Description
ChildProcess
to improve clarity and error handling.terminate_and_wait_else_kill
to encapsulate termination logic.Errno::ECHILD
andErrno::ESRCH
exceptions to correctly identify exited processes.Changes walkthrough 📝
child_process.rb
Refactor and enhance process termination and exit handling
rb/lib/selenium/webdriver/common/child_process.rb
terminate_and_wait_else_kill
.exceptions.
service_manager.rb
Add debug logging for server shutdown requests
rb/lib/selenium/webdriver/common/service_manager.rb