Skip to content

feat(client): add :keepalive_interval to keep the connection active during long waits - #671

Open
bensheldon wants to merge 2 commits into
rubycdp:mainfrom
bensheldon:feat/keepalive-interval
Open

bensheldon wants to merge 2 commits into
rubycdp:mainfrom
bensheldon:feat/keepalive-interval

Conversation

@bensheldon

Copy link
Copy Markdown

When Chrome is reached through a proxy or router with an idle timeout, any Ferrum wait longer than that timeout drops the connection. Heroku's router, for example, closes websocket connections that are idle for 55 seconds unless "either client or server [sends] an occasional ping packet". Many load balancers default to 60 seconds.

Two waits send nothing over the websocket for their whole duration:

  • Client#send_message waiting for a slow command response, e.g. Page.navigate to a page that takes a long time to respond.
  • Page#command waiting for a navigation started by the command, e.g. a click that submits a slow form.

With timeout: 120, either wait can outlast the proxy's limit. The only workaround today is to keep :timeout below that limit and retry in application code. Retrying a click can submit a form twice.

This adds an opt-in :keepalive_interval option (default nil, no behavior change):

Ferrum::Browser.new(url: "ws://chrome:3333", timeout: 120, keepalive_interval: 25)

When set, both waits are split into slices of at most keepalive_interval seconds, and a Browser.getVersion command is sent between slices. The total wait is still bounded by :timeout, and TimeoutError is raised at the same point as before.

Browser.getVersion is used because it's read-only and works at the browser level, so it still works while the page is between documents. As a real CDP round-trip, it creates traffic on every hop between Ruby and Chrome, including intermediate proxies that might answer websocket ping frames themselves.

…uring long waits

A proxy between Ruby and Chrome with an idle timeout (e.g. Heroku's router
at 55 seconds) drops the websocket when a single wait sends nothing for
longer than that, such as a slow Page.navigate response or a navigation
started by a click. With :keepalive_interval set, these waits are split
into slices with a Browser.getVersion command sent between them. The total
wait is still bounded by :timeout.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant