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

Have Ktor automatically load platform-specific native transport dependencies for Netty, if available #1672

Open
volkert-fastned opened this issue Feb 24, 2020 · 1 comment

Comments

@volkert-fastned
Copy link

volkert-fastned commented Feb 24, 2020

NOTE: this issue at first glance may seem a duplicate of #1122, but that's not the case. In the other issue, Ktor is enhanced to automatically load the native transports, if found in the classpath. This new issue however, is about automatically including the platform-specific transitive dependencies (the ones with platform-specific classifiers) when including the Ktor dependencies in a project.

Subsystem
N/A

Is your feature request related to a problem? Please describe.
It has been reported multiple times that Netty logs a number of exceptions to the console at the DEBUG level while trying to load a native transport library on application startup. It then fails to do so and falls back to the standard multiplatform NIO transport, which results in somewhat reduced performance.

Currently, I'm using the following workaround in the dependencies block of the build.gradle.kts file (assuming Gradle with Kotlin DSL), to smartly load the platform-specific native transport dependencies, if available for the underlying platform:

dependencies {
    // Your project-specific dependencies here
    // implementation("...")
    // implementation("...")
    // ...etc.

    fun determineTransitiveNettyVersion(): String? {
        var determinedNettyVersion: String? = null
        components.all {
            allVariants {
                withDependencies {
                    forEach { dep ->
                        if (dep.group == "io.netty" && dep.name == "netty-common") {
                            dep.version {
                                determinedNettyVersion = requiredVersion
                            }
                        }
                    }
                }
            }
        }
        return determinedNettyVersion
    }

    // Try to use a native transport for Netty, for increased performance, if available for the current OS type.
    // See https://netty.io/wiki/native-transports.html
    val currentOS = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.getCurrentOperatingSystem()
    val currentArch = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.getCurrentArchitecture()
    if (currentArch.isAmd64) {
        val transitiveNettyVersion = determineTransitiveNettyVersion()
        if (currentOS.isLinux) {
            implementation("io.netty:netty-transport-native-epoll:$transitiveNettyVersion:linux-x86_64")
        } else if (currentOS.isMacOsX || currentOS.isFreeBSD) {
            implementation("io.netty:netty-transport-native-kqueue:$transitiveNettyVersion:osx-x86_64")
        } else {
            println(
                "No Netty native transport available for OS \"${currentOS.name}\". Netty will fall back to using the " +
                    "NIO transport."
            )
        }
    } else {
        println(
            "No Netty native transport available for architecture \"${currentArch.name}\". Netty will fall back " +
                "to using the NIO transport."
        )
    }
}

Describe the solution you'd like
It would be convenient if Ktor could somehow handle this automatically, if possible. To be honest however, I'm not sure if there is a solution that would automagically work for transitive dependencies with classifiers, let alone one that would work in both Gradle and Maven projects.

Bonus points if there is a way to suppress the remaining debug-level exceptions that Netty will still always throw, since it always first tries multiple unsuccessful alternative ways of loading the library, even if it ultimately succeeds. But this might be better dealt with upstream in the Netty project.

And finally, log only a single message about native transport not being available when the loading of such a library was ultimately unsuccessful (for instance, when the application is deployed on a platform for which no native transport is available in Maven Central, JCenter, etc). This instead of the "successfully loaded..." message that Netty normally logs on success.

Motivation to include to ktor
It saves the hassle of configuring something that basically everybody wants: more optimal performance and resource usage efficiency for free and without any effort, if available.

Alternative proposal

If this proves infeasible, then please extend the Ktor documentation with instructions on how to add the necessary platform-specific native transport dependencies to Gradle or Maven projects. Feel free to use the workaround code I shared above.

@oleg-larshin
Copy link

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants