0
# Server Engines
1
2
Ktor's server engine system provides flexible deployment options through multiple engine implementations. The engine architecture separates application logic from server infrastructure, enabling the same application to run on different server technologies.
3
4
## ApplicationEngine Interface
5
6
### Core Engine Interface
7
8
```kotlin { .api }
9
interface ApplicationEngine {
10
val environment: ApplicationEnvironment
11
12
fun start(wait: Boolean = false): ApplicationEngine
13
suspend fun startSuspend(wait: Boolean = false): ApplicationEngine
14
fun stop(gracePeriodMillis: Long = 500, timeoutMillis: Long = 500)
15
suspend fun resolvedConnectors(): List<EngineConnectorConfig>
16
}
17
```
18
19
### Engine Lifecycle
20
21
```kotlin { .api }
22
// Start server and optionally wait
23
val engine = embeddedServer(Netty, port = 8080) {
24
routing {
25
get("/") { call.respondText("Hello!") }
26
}
27
}
28
29
// Start without blocking
30
engine.start(wait = false)
31
32
// Start with blocking (typical for main function)
33
engine.start(wait = true)
34
35
// Start asynchronously
36
runBlocking {
37
engine.startSuspend(wait = false)
38
// Do other work
39
delay(1000)
40
engine.stop(1000, 5000)
41
}
42
43
// Stop with grace period and timeout
44
engine.stop(
45
gracePeriodMillis = 1000, // Allow 1 second for graceful shutdown
46
timeoutMillis = 5000 // Force shutdown after 5 seconds
47
)
48
```
49
50
## ApplicationEngineFactory Interface
51
52
### Engine Factory
53
54
```kotlin { .api }
55
interface ApplicationEngineFactory<TEngine : ApplicationEngine, TConfiguration : ApplicationEngine.Configuration> {
56
fun create(
57
environment: ApplicationEnvironment,
58
configure: TConfiguration.() -> Unit = {}
59
): TEngine
60
}
61
```
62
63
### Available Engine Factories
64
65
```kotlin { .api }
66
// Netty engine (high-performance NIO)
67
object Netty : ApplicationEngineFactory<NettyApplicationEngine, NettyApplicationEngine.Configuration>
68
69
// CIO engine (coroutine-based)
70
object CIO : ApplicationEngineFactory<CIOApplicationEngine, CIOApplicationEngine.Configuration>
71
72
// Jetty engine (traditional servlet)
73
object Jetty : ApplicationEngineFactory<JettyApplicationEngine, JettyApplicationEngine.Configuration>
74
75
// Tomcat engine (traditional servlet)
76
object Tomcat : ApplicationEngineFactory<TomcatApplicationEngine, TomcatApplicationEngine.Configuration>
77
```
78
79
## Embedded Server Creation
80
81
### Basic Embedded Server
82
83
```kotlin { .api }
84
// Create embedded server with factory and configuration
85
fun <TEngine : ApplicationEngine, TConfiguration : ApplicationEngine.Configuration> embeddedServer(
86
factory: ApplicationEngineFactory<TEngine, TConfiguration>,
87
port: Int = 80,
88
host: String = "0.0.0.0",
89
configure: TConfiguration.() -> Unit = {},
90
module: Application.() -> Unit
91
): EmbeddedServer<TEngine, TConfiguration>
92
93
// Simple embedded server
94
fun main() {
95
embeddedServer(Netty, port = 8080) {
96
routing {
97
get("/") {
98
call.respondText("Hello, Ktor!")
99
}
100
}
101
}.start(wait = true)
102
}
103
```
104
105
### Advanced Embedded Server
106
107
```kotlin { .api }
108
// Create embedded server with environment
109
fun <TEngine : ApplicationEngine, TConfiguration : ApplicationEngine.Configuration> embeddedServer(
110
factory: ApplicationEngineFactory<TEngine, TConfiguration>,
111
environment: ApplicationEnvironment,
112
configure: TConfiguration.() -> Unit = {}
113
): EmbeddedServer<TEngine, TConfiguration>
114
115
// Example with custom environment
116
fun main() {
117
val environment = applicationEnvironment {
118
config = HoconApplicationConfig(ConfigFactory.load())
119
log = LoggerFactory.getLogger("Application")
120
}
121
122
embeddedServer(Netty, environment) {
123
// Netty-specific configuration
124
connectionGroupSize = 2
125
workerGroupSize = 5
126
callGroupSize = 10
127
128
connector {
129
port = 8080
130
host = "0.0.0.0"
131
}
132
133
connector {
134
port = 8443
135
host = "0.0.0.0"
136
// SSL configuration would go here
137
}
138
}.start(wait = true)
139
}
140
```
141
142
## Engine Configuration
143
144
### Base Engine Configuration
145
146
```kotlin { .api }
147
open class ApplicationEngine.Configuration {
148
var parallelism: Int = availableProcessors()
149
var connectionGroupSize: Int = parallelism
150
var workerGroupSize: Int = parallelism
151
var callGroupSize: Int = parallelism
152
var shutdownGracePeriod: Long = 1000
153
var shutdownTimeout: Long = 5000
154
155
internal val connectors = mutableListOf<EngineConnectorConfig>()
156
157
fun takeFrom(other: Configuration) {
158
// Copy configuration from another instance
159
parallelism = other.parallelism
160
connectionGroupSize = other.connectionGroupSize
161
workerGroupSize = other.workerGroupSize
162
callGroupSize = other.callGroupSize
163
shutdownGracePeriod = other.shutdownGracePeriod
164
shutdownTimeout = other.shutdownTimeout
165
}
166
}
167
```
168
169
### Connector Configuration
170
171
```kotlin { .api }
172
interface EngineConnectorConfig {
173
val type: ConnectorType
174
val host: String
175
val port: Int
176
}
177
178
enum class ConnectorType {
179
HTTP, HTTPS
180
}
181
182
// Configure connectors
183
embeddedServer(Netty, port = 8080) {
184
// Default connector is automatically created
185
186
// Add additional connectors
187
connector {
188
port = 8443
189
host = "0.0.0.0"
190
// Additional connector configuration
191
}
192
}
193
```
194
195
## Base Engine Implementation
196
197
### BaseApplicationEngine
198
199
```kotlin { .api }
200
abstract class BaseApplicationEngine(
201
environment: ApplicationEnvironment,
202
pipeline: EnginePipeline
203
) : ApplicationEngine {
204
205
override val environment: ApplicationEnvironment = environment
206
207
// Lifecycle management
208
abstract suspend fun startServer(): Unit
209
abstract suspend fun stopServer(): Unit
210
211
// Resolved connector information
212
override fun resolvedConnectors(): List<EngineConnectorConfig>
213
}
214
```
215
216
### Base Call Implementation
217
218
```kotlin { .api }
219
abstract class BaseApplicationCall(
220
application: Application
221
) : ApplicationCall {
222
223
override val application: Application = application
224
override val attributes: Attributes = Attributes()
225
226
abstract override val request: BaseApplicationRequest
227
abstract override val response: BaseApplicationResponse
228
229
// Parameter resolution
230
private val _parameters = lazy {
231
request.queryParameters + request.rawParameters
232
}
233
override val parameters: Parameters get() = _parameters.value
234
}
235
236
abstract class BaseApplicationRequest(call: ApplicationCall) : ApplicationRequest
237
abstract class BaseApplicationResponse(call: ApplicationCall) : ApplicationResponse
238
```
239
240
## Engine Pipeline
241
242
### EnginePipeline
243
244
```kotlin { .api }
245
class EnginePipeline(
246
val developmentMode: Boolean = false
247
) : Pipeline<Unit, ApplicationCall>(Before, Call) {
248
249
companion object {
250
val Before = PipelinePhase("Before")
251
val Call = PipelinePhase("Call")
252
}
253
}
254
255
// Default engine pipeline creation
256
fun defaultEnginePipeline(
257
environment: ApplicationEnvironment
258
): EnginePipeline {
259
return EnginePipeline(environment.developmentMode)
260
}
261
```
262
263
### Default Pipeline Implementation
264
265
```kotlin { .api }
266
class DefaultEnginePipeline(
267
application: Application,
268
developmentMode: Boolean = false
269
) : EnginePipeline(developmentMode) {
270
271
init {
272
// Install default pipeline phases and interceptors
273
intercept(Call) {
274
try {
275
// Execute application call pipeline
276
application.execute(call)
277
} catch (e: Throwable) {
278
handleEngineException(e)
279
}
280
}
281
}
282
}
283
```
284
285
## Environment and Configuration
286
287
### ApplicationEnvironment
288
289
```kotlin { .api }
290
interface ApplicationEnvironment {
291
val rootPath: String
292
val log: Logger
293
val config: ApplicationConfig
294
val monitor: Events
295
val developmentMode: Boolean
296
val parentCoroutineContext: CoroutineContext
297
val watchPaths: List<String>
298
}
299
```
300
301
### ApplicationEnvironmentBuilder
302
303
```kotlin { .api }
304
class ApplicationEnvironmentBuilder {
305
var rootPath: String = ""
306
var log: Logger = LoggerFactory.getLogger("Application")
307
var config: ApplicationConfig = MapApplicationConfig()
308
var developmentMode: Boolean = false
309
var parentCoroutineContext: CoroutineContext? = null
310
val watchPaths: MutableList<String> = mutableListOf()
311
312
fun build(): ApplicationEnvironment
313
}
314
315
// Create application environment
316
fun applicationEnvironment(
317
block: ApplicationEnvironmentBuilder.() -> Unit = {}
318
): ApplicationEnvironment {
319
return ApplicationEnvironmentBuilder().apply(block).build()
320
}
321
```
322
323
### Environment Configuration
324
325
```kotlin { .api }
326
// Configure environment from config file/object
327
fun ApplicationEnvironmentBuilder.configure(
328
config: ApplicationConfig
329
) {
330
this.config = config
331
332
// Extract common configuration
333
rootPath = config.propertyOrNull("ktor.deployment.rootPath")?.getString() ?: ""
334
developmentMode = config.propertyOrNull("ktor.development")?.getString()?.toBoolean() ?: false
335
336
// Configure watch paths for development
337
config.configList("ktor.deployment.watch").forEach { watchConfig ->
338
watchPaths.add(watchConfig.property("path").getString())
339
}
340
}
341
342
// Example configuration usage
343
fun createEnvironment(): ApplicationEnvironment {
344
return applicationEnvironment {
345
config = HoconApplicationConfig(ConfigFactory.load())
346
configure(config)
347
348
log = LoggerFactory.getLogger("MyApp")
349
developmentMode = System.getenv("ENVIRONMENT") != "production"
350
}
351
}
352
```
353
354
## Deployment Configuration
355
356
### Command Line Configuration
357
358
```kotlin { .api }
359
class CommandLineConfig(args: Array<String>) {
360
val port: Int
361
val host: String
362
val configPath: String?
363
val developmentMode: Boolean
364
365
// Parse command line arguments
366
init {
367
// Implementation parses -port, -host, -config, -dev arguments
368
}
369
}
370
371
// Configuration keys
372
object ConfigKeys {
373
const val applicationIdPath = "ktor.application.id"
374
const val hostConfigPath = "ktor.deployment.host"
375
const val portConfigPath = "ktor.deployment.port"
376
const val shutdownGracePeriodPath = "ktor.deployment.shutdown.gracePeriod"
377
const val shutdownTimeoutPath = "ktor.deployment.shutdown.timeout"
378
}
379
```
380
381
### Configuration Loading
382
383
```kotlin { .api }
384
// Load common configuration from ApplicationConfig
385
fun ApplicationEngine.Configuration.loadCommonConfiguration(config: ApplicationConfig) {
386
config.propertyOrNull("ktor.deployment.shutdown.gracePeriod")?.getString()?.toLong()?.let {
387
shutdownGracePeriod = it
388
}
389
390
config.propertyOrNull("ktor.deployment.shutdown.timeout")?.getString()?.toLong()?.let {
391
shutdownTimeout = it
392
}
393
394
config.propertyOrNull("ktor.deployment.connectionGroupSize")?.getString()?.toInt()?.let {
395
connectionGroupSize = it
396
}
397
398
config.propertyOrNull("ktor.deployment.workerGroupSize")?.getString()?.toInt()?.let {
399
workerGroupSize = it
400
}
401
}
402
```
403
404
## Utility Functions
405
406
### Shutdown Hooks
407
408
```kotlin { .api }
409
// Add shutdown hook to embedded server
410
fun <TEngine : ApplicationEngine, TConfiguration : ApplicationEngine.Configuration>
411
EmbeddedServer<TEngine, TConfiguration>.addShutdownHook() {
412
Runtime.getRuntime().addShutdownHook(Thread {
413
stop(1000, 5000)
414
})
415
}
416
417
// Example usage
418
fun main() {
419
val server = embeddedServer(Netty, port = 8080) {
420
routing {
421
get("/") { call.respondText("Hello!") }
422
}
423
}
424
425
server.addShutdownHook()
426
server.start(wait = true)
427
}
428
```
429
430
### Coroutine Integration
431
432
```kotlin { .api }
433
// Stop server when coroutine context is cancelled
434
suspend fun ApplicationEngine.stopServerOnCancellation() {
435
try {
436
awaitCancellation()
437
} finally {
438
stopSuspend(1000, 5000)
439
}
440
}
441
442
// Usage with structured concurrency
443
fun main() = runBlocking {
444
val server = embeddedServer(Netty, port = 8080) {
445
routing {
446
get("/") { call.respondText("Hello!") }
447
}
448
}
449
450
launch {
451
server.start()
452
server.stopServerOnCancellation()
453
}
454
455
// Server will stop when this coroutine scope completes
456
delay(60000) // Run for 1 minute
457
}
458
```
459
460
## Exception Handling
461
462
### Default Exception Handler
463
464
```kotlin { .api }
465
// Default uncaught exception handler for engines
466
class DefaultUncaughtExceptionHandler : Thread.UncaughtExceptionHandler {
467
override fun uncaughtException(t: Thread, e: Throwable) {
468
// Log uncaught exceptions
469
logger.error("Uncaught exception in thread ${t.name}", e)
470
}
471
}
472
473
// Map exceptions to HTTP status codes
474
fun defaultExceptionStatusCode(exception: Throwable): HttpStatusCode {
475
return when (exception) {
476
is NotFoundException -> HttpStatusCode.NotFound
477
is ParameterConversionException -> HttpStatusCode.BadRequest
478
is UnsupportedMediaTypeException -> HttpStatusCode.UnsupportedMediaType
479
is PayloadTooLargeException -> HttpStatusCode.PayloadTooLarge
480
else -> HttpStatusCode.InternalServerError
481
}
482
}
483
```
484
485
## Deployment Examples
486
487
### Production Deployment
488
489
```kotlin { .api }
490
fun main() {
491
val environment = applicationEnvironment {
492
// Load configuration from application.conf
493
config = HoconApplicationConfig(ConfigFactory.load())
494
495
// Configure from config file
496
configure(config)
497
498
// Production settings
499
developmentMode = false
500
log = LoggerFactory.getLogger("ProductionApp")
501
}
502
503
val server = embeddedServer(Netty, environment) {
504
// Production configuration
505
connectionGroupSize = 4
506
workerGroupSize = 8
507
callGroupSize = 16
508
509
shutdownGracePeriod = 5000
510
shutdownTimeout = 10000
511
512
// Multiple connectors for different interfaces
513
connector {
514
port = 8080
515
host = "0.0.0.0"
516
}
517
518
connector {
519
port = 8443
520
host = "0.0.0.0"
521
// SSL configuration
522
}
523
524
connector {
525
port = 9090
526
host = "127.0.0.1" // Internal management interface
527
}
528
}
529
530
// Add shutdown hook for graceful termination
531
server.addShutdownHook()
532
533
// Start server
534
server.start(wait = true)
535
}
536
```
537
538
### Development Deployment
539
540
```kotlin { .api }
541
fun main() {
542
val server = embeddedServer(Netty, port = 8080) {
543
// Development configuration - optimized for fast restarts
544
connectionGroupSize = 1
545
workerGroupSize = 1
546
callGroupSize = 1
547
548
connector {
549
port = 8080
550
host = "127.0.0.1" // Local only
551
}
552
}
553
554
Runtime.getRuntime().addShutdownHook(Thread {
555
server.stop(100, 1000) // Faster shutdown for development
556
})
557
558
server.start(wait = true)
559
}
560
```
561
562
### Multi-Application Deployment
563
564
```kotlin { .api }
565
fun main() {
566
// Create shared environment
567
val sharedEnvironment = applicationEnvironment {
568
config = HoconApplicationConfig(ConfigFactory.load())
569
configure(config)
570
}
571
572
// API server
573
val apiServer = embeddedServer(Netty, sharedEnvironment) {
574
connector {
575
port = 8080
576
host = "0.0.0.0"
577
}
578
}
579
580
// Admin server
581
val adminServer = embeddedServer(CIO, sharedEnvironment) {
582
connector {
583
port = 8081
584
host = "127.0.0.1" // Admin interface local only
585
}
586
}
587
588
// Start both servers
589
apiServer.start(wait = false)
590
adminServer.start(wait = false)
591
592
// Keep main thread alive
593
runBlocking {
594
awaitCancellation()
595
}
596
}
597
```
598
599
## Engine-Specific Configuration
600
601
### Netty Configuration
602
603
```kotlin { .api }
604
embeddedServer(Netty, port = 8080) {
605
// Netty-specific settings
606
connectionGroupSize = 2 // Boss threads
607
workerGroupSize = 8 // Worker threads
608
callGroupSize = 16 // Call handler threads
609
610
shutdownGracePeriod = 2000
611
shutdownTimeout = 5000
612
613
// Request timeout configuration
614
requestQueueLimit = 16
615
runningLimit = 32
616
617
// TCP configuration
618
tcpKeepAlive = true
619
reuseAddress = true
620
621
connector {
622
port = 8080
623
host = "0.0.0.0"
624
}
625
}
626
```
627
628
### CIO Configuration
629
630
```kotlin { .api }
631
embeddedServer(CIO, port = 8080) {
632
// CIO-specific settings
633
connectionGroupSize = 1
634
workerGroupSize = availableProcessors()
635
callGroupSize = availableProcessors() * 2
636
637
connectionIdleTimeout = 45000
638
639
connector {
640
port = 8080
641
host = "0.0.0.0"
642
}
643
}
644
```
645
646
This comprehensive documentation covers all aspects of Ktor's server engine system, from basic embedded server creation to advanced production deployment configurations.