feat(01-02): add /ready endpoint with database connectivity check
- Add GET /ready endpoint that checks database connection - Returns 200 'ready' when connected, 503 when not - Update Routes to require DataSource dependency - Provide dataSourceLayer in Main.scala - Use 'hikari' prefix for HikariCP config to avoid ZIO config conflict
This commit is contained in:
@@ -5,7 +5,7 @@ server {
|
|||||||
port = ${?SERVER_PORT}
|
port = ${?SERVER_PORT}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Database configuration for ZIO config (used by AppConfig)
|
# Database configuration for ZIO config (used by AppConfig.DatabaseConfig)
|
||||||
database {
|
database {
|
||||||
host = "localhost"
|
host = "localhost"
|
||||||
host = ${?DB_HOST}
|
host = ${?DB_HOST}
|
||||||
@@ -20,8 +20,8 @@ database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# HikariCP configuration for Quill DataSource
|
# HikariCP configuration for Quill DataSource
|
||||||
# Reads from "database" prefix via Quill.DataSource.fromPrefix
|
# Uses separate prefix to avoid conflict with ZIO config "database" property
|
||||||
database {
|
hikari {
|
||||||
dataSourceClassName = "org.postgresql.ds.PGSimpleDataSource"
|
dataSourceClassName = "org.postgresql.ds.PGSimpleDataSource"
|
||||||
dataSource {
|
dataSource {
|
||||||
serverName = "localhost"
|
serverName = "localhost"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import zio.config.typesafe.TypesafeConfigProvider
|
|||||||
|
|
||||||
import api.Routes
|
import api.Routes
|
||||||
import _root_.config.{AppConfig as SummerConfig}
|
import _root_.config.{AppConfig as SummerConfig}
|
||||||
|
import db.QuillContext
|
||||||
|
|
||||||
object Main extends ZIOAppDefault {
|
object Main extends ZIOAppDefault {
|
||||||
|
|
||||||
@@ -29,7 +30,11 @@ object Main extends ZIOAppDefault {
|
|||||||
_ <- Console.printLine(banner)
|
_ <- Console.printLine(banner)
|
||||||
_ <- Console.printLine(s" Starting on port ${cfg.server.port}...")
|
_ <- Console.printLine(s" Starting on port ${cfg.server.port}...")
|
||||||
_ <- Console.printLine("")
|
_ <- Console.printLine("")
|
||||||
_ <- Server.serve(Routes.routes).provide(Server.defaultWithPort(cfg.server.port))
|
// Note: Migrations are NOT auto-run. Use CLI to run migrations (Phase 5).
|
||||||
|
_ <- Server.serve(Routes.routes).provide(
|
||||||
|
Server.defaultWithPort(cfg.server.port),
|
||||||
|
QuillContext.dataSourceLayer
|
||||||
|
)
|
||||||
} yield ()
|
} yield ()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,33 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
|
import zio.*
|
||||||
import zio.http.*
|
import zio.http.*
|
||||||
|
import javax.sql.DataSource
|
||||||
|
|
||||||
/** Health check endpoints
|
/** Health check endpoints
|
||||||
*
|
*
|
||||||
* Provides basic health check endpoint for load balancers and monitoring systems. The /health
|
* Provides health check endpoints for load balancers and monitoring systems.
|
||||||
* endpoint returns 200 OK when the server is running.
|
|
||||||
*
|
*
|
||||||
* Future endpoints:
|
* Endpoints:
|
||||||
* - /ready will verify database connectivity
|
* - GET /health - Returns 200 OK when server is running (liveness probe)
|
||||||
|
* - GET /ready - Returns 200 when database is connected, 503 when not (readiness probe)
|
||||||
*/
|
*/
|
||||||
object HealthRoutes {
|
object HealthRoutes {
|
||||||
|
|
||||||
val routes: Routes[Any, Response] =
|
val routes: Routes[DataSource, Response] =
|
||||||
Routes(
|
Routes(
|
||||||
Method.GET / "health" -> Handler.text("ok")
|
// Liveness probe - always 200 if server is running
|
||||||
|
Method.GET / "health" -> Handler.text("ok"),
|
||||||
|
// Readiness probe - checks database connectivity
|
||||||
|
Method.GET / "ready" -> handler {
|
||||||
|
ZIO.serviceWithZIO[DataSource] { ds =>
|
||||||
|
ZIO.attempt {
|
||||||
|
val conn = ds.getConnection
|
||||||
|
conn.close()
|
||||||
|
}.as(Response.text("ready"))
|
||||||
|
.catchAll(_ => ZIO.succeed(Response.status(Status.ServiceUnavailable)))
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import zio.http.*
|
import zio.http.*
|
||||||
|
import javax.sql.DataSource
|
||||||
|
|
||||||
/** Route composition point
|
/** Route composition point
|
||||||
*
|
*
|
||||||
@@ -8,7 +9,7 @@ import zio.http.*
|
|||||||
*/
|
*/
|
||||||
object Routes {
|
object Routes {
|
||||||
|
|
||||||
val routes: Routes[Any, Response] =
|
val routes: Routes[DataSource, Response] =
|
||||||
HealthRoutes.routes
|
HealthRoutes.routes
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,11 +27,12 @@ object QuillContext {
|
|||||||
|
|
||||||
/** DataSource layer from HikariCP configuration
|
/** DataSource layer from HikariCP configuration
|
||||||
*
|
*
|
||||||
* Reads configuration from "database" prefix in application.conf.
|
* Reads configuration from "hikari" prefix in application.conf.
|
||||||
|
* Uses separate prefix from "database" to avoid conflict with ZIO config.
|
||||||
* HikariCP manages the connection pool.
|
* HikariCP manages the connection pool.
|
||||||
*/
|
*/
|
||||||
val dataSourceLayer: ZLayer[Any, Throwable, DataSource] =
|
val dataSourceLayer: ZLayer[Any, Throwable, DataSource] =
|
||||||
Quill.DataSource.fromPrefix("database")
|
Quill.DataSource.fromPrefix("hikari")
|
||||||
|
|
||||||
/** Quill PostgreSQL context with snake_case naming
|
/** Quill PostgreSQL context with snake_case naming
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user