Add health check
This commit is contained in:
parent
9467db2382
commit
681fd635b3
@ -32,6 +32,8 @@ RUN strip -p --strip-unneeded /myjdk/lib/server/libjvm.so
|
||||
|
||||
FROM alpine
|
||||
|
||||
RUN apk add --no-cache curl
|
||||
|
||||
ENV APPLICATION_USER simplenotes
|
||||
RUN adduser -D -g '' $APPLICATION_USER
|
||||
|
||||
|
||||
12
app/src/main/kotlin/controllers/HealthCheckController.kt
Normal file
12
app/src/main/kotlin/controllers/HealthCheckController.kt
Normal file
@ -0,0 +1,12 @@
|
||||
package be.simplenotes.app.controllers
|
||||
|
||||
import be.simplenotes.persistance.DbHealthCheck
|
||||
import org.http4k.core.Request
|
||||
import org.http4k.core.Response
|
||||
import org.http4k.core.Status.Companion.OK
|
||||
import org.http4k.core.Status.Companion.SERVICE_UNAVAILABLE
|
||||
|
||||
class HealthCheckController(private val dbHealthCheck: DbHealthCheck) {
|
||||
fun healthCheck(request: Request) =
|
||||
if (dbHealthCheck.isOk()) Response(OK) else Response(SERVICE_UNAVAILABLE)
|
||||
}
|
||||
@ -1,9 +1,6 @@
|
||||
package be.simplenotes.app.modules
|
||||
|
||||
import be.simplenotes.app.controllers.BaseController
|
||||
import be.simplenotes.app.controllers.NoteController
|
||||
import be.simplenotes.app.controllers.SettingsController
|
||||
import be.simplenotes.app.controllers.UserController
|
||||
import be.simplenotes.app.controllers.*
|
||||
import be.simplenotes.app.views.BaseView
|
||||
import be.simplenotes.app.views.NoteView
|
||||
import be.simplenotes.app.views.SettingView
|
||||
@ -16,6 +13,7 @@ val userModule = module {
|
||||
}
|
||||
|
||||
val baseModule = module {
|
||||
single { HealthCheckController(get()) }
|
||||
single { BaseController(get()) }
|
||||
single { BaseView(get()) }
|
||||
}
|
||||
|
||||
@ -45,6 +45,7 @@ val serverModule = module {
|
||||
get(),
|
||||
get(),
|
||||
get(),
|
||||
get(),
|
||||
requiredAuth = get(AuthType.Required.qualifier),
|
||||
optionalAuth = get(AuthType.Optional.qualifier),
|
||||
apiAuth = get(named("apiAuthFilter")),
|
||||
|
||||
@ -2,10 +2,7 @@ package be.simplenotes.app.routes
|
||||
|
||||
import be.simplenotes.app.api.ApiNoteController
|
||||
import be.simplenotes.app.api.ApiUserController
|
||||
import be.simplenotes.app.controllers.BaseController
|
||||
import be.simplenotes.app.controllers.NoteController
|
||||
import be.simplenotes.app.controllers.SettingsController
|
||||
import be.simplenotes.app.controllers.UserController
|
||||
import be.simplenotes.app.controllers.*
|
||||
import be.simplenotes.app.filters.*
|
||||
import be.simplenotes.domain.security.JwtPayload
|
||||
import org.http4k.core.*
|
||||
@ -22,6 +19,7 @@ class Router(
|
||||
private val settingsController: SettingsController,
|
||||
private val apiUserController: ApiUserController,
|
||||
private val apiNoteController: ApiNoteController,
|
||||
private val healthCheckController: HealthCheckController,
|
||||
private val requiredAuth: Filter,
|
||||
private val optionalAuth: Filter,
|
||||
private val apiAuth: Filter,
|
||||
@ -31,7 +29,11 @@ class Router(
|
||||
) {
|
||||
operator fun invoke(): RoutingHttpHandler {
|
||||
|
||||
val basicRoutes = ImmutableFilter.then(static(Classpath("/static"), "woff2" to ContentType("font/woff2")))
|
||||
val basicRoutes =
|
||||
routes(
|
||||
"/health" bind GET to healthCheckController::healthCheck,
|
||||
ImmutableFilter.then(static(Classpath("/static"), "woff2" to ContentType("font/woff2")))
|
||||
)
|
||||
|
||||
val publicRoutes = routes(
|
||||
"/" bind GET public baseController::index,
|
||||
|
||||
@ -11,7 +11,11 @@ simplenotes.be {
|
||||
import strict-transport
|
||||
header -Server
|
||||
|
||||
reverse_proxy http://localhost:8080
|
||||
reverse_proxy http://localhost:8080 {
|
||||
health_path /health
|
||||
health_interval 5s
|
||||
health_timeout 200ms
|
||||
}
|
||||
}
|
||||
|
||||
dev.simplenotes.be {
|
||||
|
||||
@ -19,8 +19,10 @@ services:
|
||||
volumes:
|
||||
- notes-db-volume:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
|
||||
timeout: 10s
|
||||
test: "mysql --protocol=tcp -u simplenotes -p$MYSQL_PASSWORD -e 'show databases'"
|
||||
interval: 5s
|
||||
timeout: 1s
|
||||
start_period: 2s
|
||||
retries: 10
|
||||
|
||||
simplenotes:
|
||||
@ -39,6 +41,12 @@ services:
|
||||
# - PASSWORD
|
||||
ports:
|
||||
- 127.0.0.1:8080:8080
|
||||
healthcheck:
|
||||
test: "curl --fail -s http://localhost:8080/health"
|
||||
interval: 5s
|
||||
timeout: 1s
|
||||
start_period: 2s
|
||||
retries: 3
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
|
||||
28
persistance/src/main/kotlin/HealthCheck.kt
Normal file
28
persistance/src/main/kotlin/HealthCheck.kt
Normal file
@ -0,0 +1,28 @@
|
||||
package be.simplenotes.persistance
|
||||
|
||||
import be.simplenotes.persistance.utils.DbType
|
||||
import be.simplenotes.persistance.utils.type
|
||||
import be.simplenotes.shared.config.DataSourceConfig
|
||||
import me.liuwj.ktorm.database.Database
|
||||
import me.liuwj.ktorm.database.asIterable
|
||||
import java.sql.SQLTransientException
|
||||
|
||||
interface DbHealthCheck {
|
||||
fun isOk(): Boolean
|
||||
}
|
||||
|
||||
internal class DbHealthCheckImpl(
|
||||
private val db: Database,
|
||||
private val dataSourceConfig: DataSourceConfig,
|
||||
) : DbHealthCheck {
|
||||
override fun isOk() = if (dataSourceConfig.type() == DbType.H2) true
|
||||
else try {
|
||||
db.useConnection { connection ->
|
||||
connection.prepareStatement("""SHOW DATABASES""").use {
|
||||
it.executeQuery().asIterable().map { it.getString(1) }
|
||||
}
|
||||
}.any { it in dataSourceConfig.jdbcUrl }
|
||||
} catch (e: SQLTransientException) {
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -1,18 +1,24 @@
|
||||
package be.simplenotes.persistance
|
||||
|
||||
import be.simplenotes.persistance.utils.DbType
|
||||
import be.simplenotes.persistance.utils.type
|
||||
import be.simplenotes.shared.config.DataSourceConfig
|
||||
import org.flywaydb.core.Flyway
|
||||
import javax.sql.DataSource
|
||||
|
||||
interface DbMigrations {
|
||||
fun migrate()
|
||||
}
|
||||
|
||||
internal class DbMigrationsImpl(
|
||||
private val dataSource: DataSource,
|
||||
private val dataSourceConfig: DataSourceConfig
|
||||
private val dataSourceConfig: DataSourceConfig,
|
||||
) : DbMigrations {
|
||||
override fun migrate() {
|
||||
|
||||
val migrationDir = when {
|
||||
dataSourceConfig.jdbcUrl.contains("mariadb") -> "db/migration/mariadb"
|
||||
else -> "db/migration/other"
|
||||
val migrationDir = when (dataSourceConfig.type()) {
|
||||
DbType.H2 -> "db/migration/other"
|
||||
DbType.MariaDb -> "db/migration/mariadb"
|
||||
}
|
||||
|
||||
Flyway.configure()
|
||||
@ -13,10 +13,6 @@ import org.koin.dsl.module
|
||||
import org.koin.dsl.onClose
|
||||
import javax.sql.DataSource
|
||||
|
||||
interface DbMigrations {
|
||||
fun migrate()
|
||||
}
|
||||
|
||||
private fun hikariDataSource(conf: DataSourceConfig): HikariDataSource {
|
||||
val hikariConfig = HikariConfig().also {
|
||||
it.jdbcUrl = conf.jdbcUrl
|
||||
@ -41,4 +37,5 @@ val persistanceModule = module {
|
||||
get<DbMigrations>().migrate()
|
||||
Database.connect(get<DataSource>())
|
||||
}
|
||||
single<DbHealthCheck> { DbHealthCheckImpl(get(), get()) }
|
||||
}
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
package be.simplenotes.persistance.utils
|
||||
|
||||
import be.simplenotes.shared.config.DataSourceConfig
|
||||
|
||||
enum class DbType { H2, MariaDb }
|
||||
|
||||
fun DataSourceConfig.type(): DbType = if (jdbcUrl.contains("mariadb")) DbType.MariaDb
|
||||
else DbType.H2
|
||||
Loading…
x
Reference in New Issue
Block a user