-
-
Notifications
You must be signed in to change notification settings - Fork 8.6k
Description
What happened?
Hello,
Apologies for the vague title, but it completely summarizes what we've been experiencing.
When running this code with a profiler, we discovered that send_remote_shutdown_command is taking >30 seconds to finish.
To get to the bottom of the issue, we monkey-patched this function. This gave us an unexpected output. .quit() was only called 3 times, but the output shows that send_remote_shutdown_command was called 6 times. I think it's because __exit__ is being called by the with statement.
selenium/py/selenium/webdriver/remote/webdriver.py
Lines 216 to 222 in ba27d0f
| def __exit__( | |
| self, | |
| exc_type: typing.Optional[typing.Type[BaseException]], | |
| exc: typing.Optional[BaseException], | |
| traceback: typing.Optional[types.TracebackType], | |
| ): | |
| self.quit() |
On macOS and Linux, calling quit() twice is quick because the default TCP socket timeout is low. However on Windows, the default timeout is long.
| request.urlopen(f"{self.service_url}/shutdown") |
Solution
We're working around this issue on Windows by monkey-patching the function and setting the timeout to a small value.
from selenium.webdriver.common.service import Service
from urllib import request
from urllib.error import URLError
def send_remote_shutdown_command(self) -> None:
try:
request.urlopen(f"{self.service_url}/shutdown", timeout=0.1)
except URLError:
return
Service.send_remote_shutdown_command = send_remote_shutdown_commandHow can we reproduce the issue?
import threading
from concurrent.futures import ThreadPoolExecutor
from selenium.webdriver import Chrome
from selenium.webdriver.common.service import Service
fn_copy = Service.send_remote_shutdown_command
count = 0
mut = threading.Lock()
def send_remote_shutdown_command(self: Service) -> None:
global count
with mut:
count += 1
print(f"CALLED: {count} times")
fn_copy(self)
Service.send_remote_shutdown_command = send_remote_shutdown_command
class MyObject:
def __init__(self, id):
self.id = id
objects = [MyObject(i) for i in range(3)]
def run(obj):
chrome = Chrome()
obj.browser = chrome
chrome.get("https://www.google.com")
print("quit", obj.id)
chrome.quit()
with ThreadPoolExecutor(max_workers=1) as executor:
for result in executor.map(run, objects):
print("result")
print("script complete")Relevant log output
quit 0
CALLED: 1 times
CALLED: 2 times
quit 1
CALLED: 3 times
CALLED: 4 times
quit 2
CALLED: 5 times
CALLED: 6 times
script completeOperating System
Windows 10
Selenium version
4.19.0
What are the browser(s) and version(s) where you see this issue?
124.0.6367.60
What are the browser driver(s) and version(s) where you see this issue?
ChromeDriver 123.0.6312.122
Are you using Selenium Grid?
No response