Skip to content
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

allow configuring web socket close timeout #8189

Merged
merged 1 commit into from
Mar 31, 2024
Merged

allow configuring web socket close timeout #8189

merged 1 commit into from
Mar 31, 2024

Conversation

ArloL
Copy link
Contributor

@ArloL ArloL commented Jan 13, 2024

The default timeout of 60 seconds is too high for one of my use cases. I tried my best to match the existing API. Please feel free to give me feedback on how I can make this as good as possible to increase the likelihood of it being merged.

PS Thanks for the efforts maintaining critical infrastructure like this library.

Edit: Figured it out. My JVM was set to Java 8 SDK. I sadly could not run `./gradlew checks`. I included the errors I got.
❯ ./gradlew checks                                                  
To honour the JVM settings for this build a single-use Daemon process will be forked. For more on this, please refer to https://docs.gradle.org/8.5/userguide/gradle_daemon.html#sec:disabling_the_daemon in the Gradle documentation.
Daemon will be stopped at the end of the build 
Type-safe project accessors is an incubating feature.
Project accessors enabled, but root project name not explicitly set for 'buildSrc'. Checking out the project in different folders will impact the generated code and implicitly the buildscript classpath, breaking caching.

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring root project 'okhttp-parent'.
> Could not resolve all files for configuration ':classpath'.
   > Could not resolve de.mannodermaus.gradle.plugins:android-junit5:1.10.0.0.
     Required by:
         project :
      > No matching variant of de.mannodermaus.gradle.plugins:android-junit5:1.10.0.0 was found. The consumer was configured to find a library for use during runtime, compatible with Java 8, packaged as a jar, and its dependencies declared externally, as well as attribute 'org.gradle.plugin.api-version' with value '8.5' but:
          - Variant 'apiElements' capability de.mannodermaus.gradle.plugins:android-junit5:1.10.0.0 declares a library, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component for use during compile-time, compatible with Java 11 and the consumer needed a component for use during runtime, compatible with Java 8
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
          - Variant 'runtimeElements' capability de.mannodermaus.gradle.plugins:android-junit5:1.10.0.0 declares a library for use during runtime, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component, compatible with Java 11 and the consumer needed a component, compatible with Java 8
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
   > Could not resolve com.android.tools.build:gradle:8.2.0.
     Required by:
         project :
      > No matching variant of com.android.tools.build:gradle:8.2.0 was found. The consumer was configured to find a library for use during runtime, compatible with Java 8, packaged as a jar, and its dependencies declared externally, as well as attribute 'org.gradle.plugin.api-version' with value '8.5' but:
          - Variant 'apiElements' capability com.android.tools.build:gradle:8.2.0 declares a library, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component for use during compile-time, compatible with Java 11 and the consumer needed a component for use during runtime, compatible with Java 8
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
          - Variant 'javadocElements' capability com.android.tools.build:gradle:8.2.0 declares a component for use during runtime, and its dependencies declared externally:
              - Incompatible because this component declares documentation and the consumer needed a library
              - Other compatible attributes:
                  - Doesn't say anything about its target Java version (required compatibility with Java 8)
                  - Doesn't say anything about its elements (required them packaged as a jar)
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
          - Variant 'runtimeElements' capability com.android.tools.build:gradle:8.2.0 declares a library for use during runtime, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component, compatible with Java 11 and the consumer needed a component, compatible with Java 8
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
          - Variant 'sourcesElements' capability com.android.tools.build:gradle:8.2.0 declares a component for use during runtime, and its dependencies declared externally:
              - Incompatible because this component declares documentation and the consumer needed a library
              - Other compatible attributes:
                  - Doesn't say anything about its target Java version (required compatibility with Java 8)
                  - Doesn't say anything about its elements (required them packaged as a jar)
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
   > Could not resolve com.diffplug.spotless:spotless-plugin-gradle:6.23.3.
     Required by:
         project :
      > No matching variant of com.diffplug.spotless:spotless-plugin-gradle:6.23.3 was found. The consumer was configured to find a library for use during runtime, compatible with Java 8, packaged as a jar, and its dependencies declared externally, as well as attribute 'org.gradle.plugin.api-version' with value '8.5' but:
          - Variant 'apiElements' capability com.diffplug.spotless:spotless-plugin-gradle:6.23.3 declares a library, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component for use during compile-time, compatible with Java 11 and the consumer needed a component for use during runtime, compatible with Java 8
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
          - Variant 'javadocElements' capability com.diffplug.spotless:spotless-plugin-gradle:6.23.3 declares a component for use during runtime, and its dependencies declared externally:
              - Incompatible because this component declares documentation and the consumer needed a library
              - Other compatible attributes:
                  - Doesn't say anything about its target Java version (required compatibility with Java 8)
                  - Doesn't say anything about its elements (required them packaged as a jar)
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
          - Variant 'runtimeElements' capability com.diffplug.spotless:spotless-plugin-gradle:6.23.3 declares a library for use during runtime, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component, compatible with Java 11 and the consumer needed a component, compatible with Java 8
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
          - Variant 'sourcesElements' capability com.diffplug.spotless:spotless-plugin-gradle:6.23.3 declares a component for use during runtime, and its dependencies declared externally:
              - Incompatible because this component declares documentation and the consumer needed a library
              - Other compatible attributes:
                  - Doesn't say anything about its target Java version (required compatibility with Java 8)
                  - Doesn't say anything about its elements (required them packaged as a jar)
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
   > Could not resolve com.vanniktech:gradle-maven-publish-plugin:0.27.0.
     Required by:
         project :
      > No matching variant of com.vanniktech:gradle-maven-publish-plugin:0.27.0 was found. The consumer was configured to find a library for use during runtime, compatible with Java 8, packaged as a jar, and its dependencies declared externally, as well as attribute 'org.gradle.plugin.api-version' with value '8.5' but:
          - Variant 'apiElements' capability com.vanniktech:gradle-maven-publish-plugin:0.27.0 declares a library, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component for use during compile-time, compatible with Java 11 and the consumer needed a component for use during runtime, compatible with Java 8
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
          - Variant 'runtimeElements' capability com.vanniktech:gradle-maven-publish-plugin:0.27.0 declares a library for use during runtime, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component, compatible with Java 11 and the consumer needed a component, compatible with Java 8
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')
          - Variant 'sourcesElements' capability com.vanniktech:gradle-maven-publish-plugin:0.27.0 declares a component for use during runtime, and its dependencies declared externally:
              - Incompatible because this component declares documentation and the consumer needed a library
              - Other compatible attributes:
                  - Doesn't say anything about its target Java version (required compatibility with Java 8)
                  - Doesn't say anything about its elements (required them packaged as a jar)
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.5')

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

BUILD FAILED in 5s
4 actionable tasks: 1 executed, 3 up-to-date

Copy link
Collaborator

@yschimke yschimke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does feel like something that has currently been arbitrarily selected, so making it tunable makes sense.

Reading https://datatracker.ietf.org/doc/html/rfc6455#section-7 the only 2 things that might worry me are

The underlying TCP connection, in most normal cases, SHOULD be closed
first by the server, so that it holds the TIME_WAIT state and not the
client (as this would prevent it from re-opening the connection for 2
maximum segment lifetimes (2MSL), while there is no corresponding
server impact as a TIME_WAIT connection is immediately reopened upon
a new SYN with a higher seq number). In abnormal cases (such as not
having received a TCP Close from the server after a reasonable amount
of time) a client MAY initiate the TCP Close.

and

To prevent this, clients SHOULD use some form of backoff when trying
to reconnect after abnormal closures as described in this section.

Basically whether setting this to really small values leads to failure to reconnect or DOS from resuming in these abnormal closure situations.

But @swankjesse might know more.

@yschimke
Copy link
Collaborator

e: file:///home/runner/work/okhttp/okhttp/okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt:257:33 Type mismatch: inferred type is Long but Int was expected
e: file:///home/runner/work/okhttp/okhttp/okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt:615:27 Type mismatch: inferred type is Int but Long was expected
e: file:///home/runner/work/okhttp/okhttp/okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt:1298:22 Type mismatch: inferred type is Int but Long was expected
e: file:///home/runner/work/okhttp/okhttp/okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt:1326:24 Type mismatch: inferred type is Int but Long was expected

@yschimke yschimke added the enhancement Feature not a bug label Jan 13, 2024
@ArloL
Copy link
Contributor Author

ArloL commented Jan 13, 2024

e: file:///home/runner/work/okhttp/okhttp/okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt:257:33 Type mismatch: inferred type is Long but Int was expected
e: file:///home/runner/work/okhttp/okhttp/okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt:615:27 Type mismatch: inferred type is Int but Long was expected
e: file:///home/runner/work/okhttp/okhttp/okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt:1298:22 Type mismatch: inferred type is Int but Long was expected
e: file:///home/runner/work/okhttp/okhttp/okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt:1326:24 Type mismatch: inferred type is Int but Long was expected

Thanks. I figured out the issue with gradle. I had my JVM set to Java 8. It works with Java 21.

Now these should be gone.

@swankjesse
Copy link
Collaborator

The default timeout of 60 seconds is too high for one of my use cases.

Could you explain your use case a bit more? I’d expect a well-behaved server to respond to a close frame immediately, so this 60 second limit shouldn’t be relevant in practice.

That said I’m happy with the shape of this PR!

@swankjesse swankjesse merged commit 66ae138 into square:master Mar 31, 2024
19 checks passed
@swankjesse
Copy link
Collaborator

Small follow-up: #8316

@ArloL ArloL deleted the feature/web-socket-close-timeout branch April 1, 2024 14:53
@ArloL
Copy link
Contributor Author

ArloL commented Apr 1, 2024

Could you explain your use case a bit more? I’d expect a well-behaved server to respond to a close frame immediately, so this 60 second limit shouldn’t be relevant in practice.

Sure. The context is an android application in an (air-gapped) Wi-Fi network environment where the mobile devices are moving and need to inform the users if the connection has been lost. So I hit this timeout in tests where the network connection was flakey and it was not a proper close of the connection; which is where the default comes in. And for my use case setting a much lower timeout (ie 10 seconds) made sense because latency is mostly not really an issue - unless it is and that is exactly what I want to know and inform the users that the notifications might be out of date.

@swankjesse
Copy link
Collaborator

Oh neat! Thanks for the explanation!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Feature not a bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants