https://kotlinlang.org logo
#ktor
Title
o

orangy

04/19/2018, 2:40 PM
I believe you shouldn’t need to start two servers, just provide two connectors. Am I right @cy?
c

cy

04/19/2018, 2:40 PM
Yes but in this case it could be more difficult to specify completely different modules and separate them
Also we don't have a route function for port
o

orangy

04/19/2018, 2:52 PM
That’s easy to fix or even write it yourself.
But then if installed features would be different, then yes
Long time ago we were thinking about running several applications in the same engine, but then decided it’s too complicated. We may revisit it.
d

dave08

04/19/2018, 3:08 PM
Is there a temporary simple way to implement it myself? Before I thought that if one fails at least one should be kept running, but now that I think of it I see that its even worse than that... Since I'm running on Docker, if one fails, Docker won't know that it's down and won't try to reschedule it... so putting both on the same server and having one health check for both would probably be the best solution...
c

cy

04/19/2018, 3:29 PM
I'd start with something like this (untested)
Copy code
data class PortRouteSelector(val ports: List<IntRange>) : RouteSelector(RouteSelectorEvaluation.qualityConstant) {
    override fun evaluate(context: RoutingResolveContext, segmentIndex: Int): RouteSelectorEvaluation {
        val callPort = context.call.request.local.port

        return if (ports.any { callPort in it }) {
            RouteSelectorEvaluation.Constant
        } else {
            RouteSelectorEvaluation.Failed
        }
    }
}

fun Route.localPort(vararg ports: Int, block: Route.() -> Unit): Route {
    return createChild(PortRouteSelector(ports.map { it..it })).apply(block)
}
d

dave08

04/19/2018, 3:31 PM
How would you get Netty to listen to the ports in the first place?
There's only one port param in
embeddedServer
...
c

cy

04/19/2018, 3:41 PM
Copy code
fun main(args: Array<String>) {
    val env = applicationEngineEnvironment {
        module { 
            main()
        }
        connector {
            port = 9090
        }
        connector {
            port = 8080
        }
        sslConnector() {
            port = 8443
        }
    }
    embeddedServer(Netty, env).start(true)
}
@Deactivated User I believe this need to be somehwere at https://ktor.io/servers/configuration.html
d

Deactivated User

04/19/2018, 3:43 PM
Yes. It seems so. Going to add it 👍
c

cy

04/19/2018, 3:44 PM
(note that sslConnector requires more parameters than I've provided in the sample)
🆗 1
Also
connector
has
host
parameter so a particular connector could listen a specific subnet/address
d

dave08

04/19/2018, 3:50 PM
So something like this could be done:
Copy code
/**
 * Creates an embedded server with the given [factory], listening on [endpoints] list of Pair(host, port)
 * @param watchPaths specifies path substrings that will be watched for automatic reloading
 * @param configure configuration script for the engine
 * @param module application module function
 */
fun <TEngine : ApplicationEngine, TConfiguration : ApplicationEngine.Configuration>
        embeddedServer(factory: ApplicationEngineFactory<TEngine, TConfiguration>,
                       endpoints: List<Pair<String, Int>> =  listOf(Pair("0.0.0.0", 80)),
                       watchPaths: List<String> = emptyList(),
                       configure: TConfiguration.() -> Unit = {},
                       module: Application.() -> Unit): TEngine {
    val environment = applicationEngineEnvironment {
        this.log = LoggerFactory.getLogger("ktor.application")
        this.watchPaths = watchPaths
        this.module(module)

        endpoints.forEach { endpoint ->
            connector {
                this.port = endpoint.first
                this.host = endpoint.second
            }
        }

    }

    return embeddedServer(factory, environment, configure)
}
In addition to the current
embeddedServer
implementation...
This could be the solution, thanks!
The only thing is that the ports would have to be repeated in the routing.. but this is certainly a good start 🙂