meldestelle/docs/database/DATABASE_DIAGNOSTIC_REPORT-en.md
2025-07-25 23:16:16 +02:00

4.9 KiB

Database Diagnostic Report - Exposed Framework Initialization

Diagnostic Results

Database.connect() Calls Identified

Central Implementation:

  • DatabaseFactory.kt (Line 66): Database.connect(dataSource!!)
    • Uses HikariCP Connection Pooling
    • Singleton pattern with proper configuration
    • Supports connection validation and leak detection

Service-specific Configurations:

  • Events Service: EventsDatabaseConfiguration.kt - uses DatabaseFactory.init()
  • Horses Service: DatabaseConfiguration.kt - uses DatabaseFactory.init()
  • Members Service: MembersDatabaseConfiguration.kt - uses DatabaseFactory.init()
  • Masterdata Service: MasterdataDatabaseConfiguration.kt - uses DatabaseFactory.init()

⚠️ PROBLEM IDENTIFIED - Gateway Configuration:

  • Gateway: DatabaseConfig.kt (Lines 25-30) - direct Database.connect() call
    Database.connect(
        url = databaseUrl,
        driver = "org.postgresql.Driver",
        user = databaseUser,
        password = databasePassword
    )
    

Exposed Operations (Transactions, Queries) Located

Schema Initialization (in @PostConstruct):

  • All Services: transaction { SchemaUtils.createMissingTablesAndColumns(...) }
  • Gateway: transaction { SchemaUtils.createMissingTablesAndColumns(...) } for all contexts

Business Logic Transactions:

  • TransactionalCreateHorseUseCase: Uses DatabaseFactory.dbQuery { ... }
  • DatabaseMigrator: Uses transaction { ... } for migrations

Test Transactions:

  • SimpleDatabaseTest.kt: Direct transaction { ... } calls in tests

Initialization Order Analyzed

Correct Order in Services:

  1. @PostConstructDatabaseFactory.init(config)Database.connect()
  2. Immediately after: transaction { SchemaUtils.createMissingTablesAndColumns(...) }
  3. Business Logic: DatabaseFactory.dbQuery { ... } for transactions

⚠️ PROBLEM - Gateway Initialization:

  1. Ktor Application.configureDatabase() → direct Database.connect()
  2. Immediately after: transaction { ... } for all service schemas

🚨 Identified Problems

1. Inconsistent Database.connect() Implementation

  • Services: Use central DatabaseFactory with Connection Pooling
  • Gateway: Direct Database.connect() without Connection Pooling
  • Risk: Different connection quality and management

2. Potential Race Conditions

  • Gateway and services initialize independently
  • Both attempt to create schemas for the same tables
  • Risk: Conflicts during parallel initialization

3. Violation of Separation of Concerns

  • Gateway manages schemas for all services
  • Services manage their own schemas
  • Risk: Duplicate schema initialization

4. Missing Initialization Order Guarantees

  • No explicit dependency order between Gateway and Services
  • Risk: Exposed operations before Database.connect()

Recommendations

1. Switch Gateway to DatabaseFactory

// Instead of direct Database.connect():
fun Application.configureDatabase() {
    val config = DatabaseConfig.fromEnv() // or from Ktor Config
    DatabaseFactory.init(config)
    // Remove or coordinate schema initialization
}

2. Coordinate Schema Initialization

Option A: Only services manage their schemas (recommended)

// Gateway: Only connection, no schema initialization
fun Application.configureDatabase() {
    DatabaseFactory.init(DatabaseConfig.fromEnv())
}

Option B: Centralized schema management

// Separate DatabaseSchemaInitializer with @Order annotation
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
class DatabaseSchemaInitializer {
    @PostConstruct
    fun initializeAllSchemas() {
        // Schema initialization logic
    }
}

3. Ensure Startup Order

// Services with @DependsOn
@Configuration
@DependsOn("databaseInitializer")
class HorsesDatabaseConfiguration {
    // Configuration logic
}

4. Unified Configuration

// All components use DatabaseFactory
class SomeService {
    suspend fun doSomething() {
        DatabaseFactory.dbQuery {
            // Exposed operations
        }
    }
}

📋 Summary

Correctly implemented:

  • All services use proper @PostConstruct → Database.connect() → Exposed operations sequence
  • DatabaseFactory provides robust Connection Pool configuration
  • Business logic uses correct transaction patterns

⚠️ To be fixed:

  • Gateway Database.connect() inconsistency
  • Potential race conditions in schema initialization
  • Missing startup order coordination

🎯 Priority:

  1. High: Switch Gateway to DatabaseFactory
  2. Medium: Coordinate schema initialization
  3. Low: Explicitly define startup order

The initialization sequence is fundamentally correct, but the inconsistency between Gateway and Services should be resolved to avoid potential problems.


Last updated: July 25, 2025