-
Notifications
You must be signed in to change notification settings - Fork 455
/
Copy pathKtorServer.kt
100 lines (95 loc) · 4.43 KB
/
KtorServer.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package arrow.continuations.ktor
import arrow.fx.coroutines.Resource
import arrow.fx.coroutines.ResourceScope
import io.ktor.server.application.*
import io.ktor.server.engine.*
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.delay
import kotlinx.io.files.Path
import kotlinx.io.files.SystemFileSystem
/**
* Ktor [ApplicationEngine] as a [Resource]. This [Resource] will gracefully shut down the server
* When we need to shut down a Ktor service we need to properly take into account a _grace_ period
* where we still handle requests instead of immediately cancelling any in-flight requests.
*
* @param factory Application engine for processing the requests
* @param port Server listening port. Default is set to 80
* @param host Host address. Default is set to "0.0.0.0"
* @param watchPaths specifies path substrings that will be watched for automatic reloading
* @param preWait preWait a duration to wait before beginning the stop process. During this time,
* requests will continue to be accepted. This setting is useful to allow time for the container
* to be removed from the load balancer. This is disabled when `io.ktor.development=true`.
* @param grace grace a duration during which already inflight requests are allowed to continue
* before the shutdown process begins.
* @param timeout timeout a duration after which the server will be forcibly shutdown.
* @param module Represents configured and running web application, capable of handling requests.
*/
public suspend fun <
TEngine : ApplicationEngine,
TConfiguration : ApplicationEngine.Configuration,
> ResourceScope.server(
factory: ApplicationEngineFactory<TEngine, TConfiguration>,
port: Int = 80,
host: String = "0.0.0.0",
watchPaths: List<String> = listOf(WORKING_DIRECTORY_PATH),
preWait: Duration = 30.seconds,
grace: Duration = 500.milliseconds,
timeout: Duration = 500.milliseconds,
module: Application.() -> Unit = {},
): EmbeddedServer<TEngine, TConfiguration> =
install({
embeddedServer(factory, host = host, port = port, watchPaths = watchPaths, module = module)
.apply(EmbeddedServer<TEngine, TConfiguration>::start)
}) { engine, _ ->
engine.release(preWait, grace, timeout)
}
/**
* Ktor [ApplicationEngine] as a [Resource]. This [Resource] will gracefully shut down the server
* When we need to shut down a Ktor service we need to properly take into account a _grace_ period
* where we still handle requests instead of immediately cancelling any in-flight requests.
*
* @param factory Application engine for processing the requests
* @param rootConfig definition of the core configuration of the server, including modules, paths,
* and environment details.
* @param preWait preWait a duration to wait before beginning the stop process. During this time,
* requests will continue to be accepted. This setting is useful to allow time for the container
* to be removed from the load balancer. This is disabled when `io.ktor.development=true`.
* @param grace grace a duration during which already inflight requests are allowed to continue
* before the shutdown process begins.
* @param timeout timeout a duration after which the server will be forcibly shutdown.
*/
public suspend fun <
TEngine : ApplicationEngine,
TConfiguration : ApplicationEngine.Configuration,
> ResourceScope.server(
factory: ApplicationEngineFactory<TEngine, TConfiguration>,
rootConfig: ServerConfig,
configure: TConfiguration.() -> Unit = {},
preWait: Duration = 30.seconds,
grace: Duration = 500.milliseconds,
timeout: Duration = 500.milliseconds,
): EmbeddedServer<TEngine, TConfiguration> =
install({
embeddedServer(factory, rootConfig, configure)
.apply(EmbeddedServer<TEngine, TConfiguration>::start)
}) { engine, _ ->
engine.release(preWait, grace, timeout)
}
private suspend fun EmbeddedServer<*, *>.release(
preWait: Duration,
grace: Duration,
timeout: Duration,
) {
if (!application.developmentMode) {
environment.log.info(
"prewait delay of ${preWait.inWholeMilliseconds}ms, turn it off using io.ktor.development=true"
)
delay(preWait.inWholeMilliseconds)
}
environment.log.info("Shutting down HTTP server...")
stop(grace.inWholeMilliseconds, timeout.inWholeMicroseconds)
environment.log.info("HTTP server shutdown!")
}
internal val WORKING_DIRECTORY_PATH: String = SystemFileSystem.resolve(Path(".")).toString()