Skip to content

Should use HTTP keep alive to avoid port exhaustion #5758

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
awarecan opened this issue Apr 11, 2018 · 16 comments · Fixed by #5759
Closed

Should use HTTP keep alive to avoid port exhaustion #5758

awarecan opened this issue Apr 11, 2018 · 16 comments · Fixed by #5759
Labels
C-dotnet .NET Bindings C-nodejs JavaScript Bindings

Comments

@awarecan
Copy link
Contributor

awarecan commented Apr 11, 2018

Meta -

OS: Windows 7, 10
Selenium Version: 3.8.1
Browser: Chrome
Browser Version: 65.0.3325.181 (64-bit)
Node.js: 8.11.1

Expected Behavior -

During the test, TCP connection should be reused

Actual Behavior -

Each WebDriver command will create a new TCP connection to ChromeDriver

Steps to reproduce -

await browser.get('https://www.google.com/');
for (let i=0; i<50000; i++) {
  await browser.getCurrentUrl();
}

use netstat -na to monitor the number of TCP connection in TIME_WAIT state while you are running above code. You will see massive amount of TCP connections. If you are using a powerful box and has default Windows TCP/IP configuration, you will hit ephemeral port exhaustion very soon.

Note -

This was a well known issue related with ChromeDriver. However ChromeDriver has a dirty fix in 2.35 release. It requires client set Connection: keep-alive HTTP header, see the discussion in #4162 and #3457

Now, we finally have chance to resolve this issue in selenium-webdriver side by passing in an Agent with keepAlive option while creating HttpClient in createExecutor() function.

awarecan added a commit to awarecan/selenium that referenced this issue Apr 11, 2018
@p0deje p0deje added C-py Python Bindings C-rb Ruby Bindings C-dotnet .NET Bindings C-java Java Bindings C-nodejs JavaScript Bindings D-chrome labels Apr 11, 2018
@p0deje
Copy link
Member

p0deje commented Apr 11, 2018

Seems like we need to do this for all the bindings.

@barancev
Copy link
Member

In Java I can't reproduce this issue with chromedriver, but the number of TIME_WAIT'ing ports grows if I use geckodriver.

@dmytro-verner
Copy link

dmytro-verner commented Apr 23, 2018

@barancev possibly you have registry's HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters (in case of Windows) TcpTimedWaitDelay set to non-default value(the default one is 240 secs).

Setting this value to a lower bound(e.g. 30 secs) can help to circumvent the current issue.

@barancev barancev changed the title Should use HTTP keep alive for chrome driver to avoid port exhaustion Should use HTTP keep alive to avoid port exhaustion May 7, 2018
@barancev
Copy link
Member

barancev commented May 7, 2018

It appears that OkHttp uses keep-alive by default, so it's not an issue with Java binding.

@p0deje
Copy link
Member

p0deje commented May 18, 2018

Since there is no straightforward way to use keep-alive connections in standard Ruby library, I think we'll just stick to existing solution described in wiki. One needs to install net-http-persistent gem and use Persistent HTTP client. We might consider making it a runtime dependency and use by default, but that's subject for discussion.

@p0deje p0deje removed the C-rb Ruby Bindings label May 18, 2018
@ariasuni
Copy link

Are there any known workaround for the Python bindings?

@lmtierney
Copy link
Member

@ariasuni you can currently set keep_alive on a Remote webdriver instance. Currently it's not in the individual drivers, but you could always start up the driver binary yourself and use Remote to connect to it as a workaround. Which drivers do we know support keep alive? We can add it to those xtors.

- keep_alive - Whether to configure remote_connection.RemoteConnection to use

@ariasuni
Copy link

Unfortunately, your solution is more a refactoring, and it would require me to modify a ton of production code which I can’t do.

It worked perfectly fine for me with 2.53.* but not any 3.*, thus I can’t upgrade and use recent versions of Firefox or Chromium.

@awarecan
Copy link
Contributor Author

awarecan commented May 24, 2018

Python should support ChromeDriver keep-alive option already

def __init__(self, remote_server_addr, keep_alive=True):

@ariasuni I don't know why @barancev removed ChromeDriver from my issue subject. As I explained in the beginning, this issue is ChromeDriver specific. If you have problem with Firefox, I suggest you open a new issue to tracking.

@ariasuni
Copy link

Well, I have this problem with PhantomJS but I guess that it won’t be resolved if it’s specific to this webdriver.

@secondcircle
Copy link

Anyone know if there is a fix for chromedriver with C#? I'm running into this same port exhaustion issue only with chromedriver.

@awarecan
Copy link
Contributor Author

awarecan commented May 25, 2018

@secondcircle Could you double check your chromeDriver version? The keep-live feature is only available on 2.35 and after.

From the code I read, RemoteDriver should support keep-alive by default, and ChromeDriver just a simple extension of RemoteDriver

public DriverServiceCommandExecutor(DriverService driverService, TimeSpan commandTimeout)

@barancev
Copy link
Member

@awarecan I've expanded the issue from python to other bindings too. At the same time I've removed "browser"-label because we only can fix client bindings. But this will have effect only for the drivers that provide support for keep-alive. It seems that chromedriver supports it, so we can use this driver to test client bindings.

If python binding has implemented keep-alive support we can remove this label from this issue, but I want to get a confirmation from the python part of the team. The same for C#.

@awarecan
Copy link
Contributor Author

@secondcircle I realized the dotNet binding issue now. I actually point to the right issue in the beginning of this thread, please check #4162 that is about dotNet binding and chromeDriver 2.35

@barancev I don't have time to check what happens in python and C# language binding, I bet #4162 points to the root cause, the chromeDriver 2.35's implementation may have issue with the HTTP 1.1 client, have to set Connection: keep-alive header explicitly to make it works

@awarecan
Copy link
Contributor Author

To whom may have interesting, mozilla/geckodriver#713 is the discussion in geckodriver project

@lmtierney
Copy link
Member

As stated, keep_alive is already used for Chrome in python, removing label.

@lmtierney lmtierney removed the C-py Python Bindings label Jun 26, 2018
jleyba pushed a commit that referenced this issue Dec 15, 2018
* turn on http keep alive while using ChromeDriver

need chrome driver 2.35 or above
fix #5758

* add ECONNREFUSED as retryable network error

after enable HTTP keep alive, chromedriver sometimes refused connection
shs96c pushed a commit to shs96c/selenium that referenced this issue Feb 18, 2019
* turn on http keep alive while using ChromeDriver

need chrome driver 2.35 or above
fix SeleniumHQ#5758

* add ECONNREFUSED as retryable network error

after enable HTTP keep alive, chromedriver sometimes refused connection
@lock lock bot locked and limited conversation to collaborators Aug 15, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
C-dotnet .NET Bindings C-nodejs JavaScript Bindings
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants