chore: erweitere Resilience4j-Bundle um Kotlin-Support, aktualisiere PingController um Fallback-Logik, füge Fehlerhandler hinzu, verbessere PingControllerTest, synchronisiere .env und dc-infra.yaml
This commit is contained in:
+17
-8
@@ -2,6 +2,7 @@ package at.mocode.ping.infrastructure.web
|
||||
|
||||
import at.mocode.ping.api.*
|
||||
import at.mocode.ping.application.PingUseCase
|
||||
import at.mocode.ping.domain.Ping
|
||||
import at.mocode.ping.infrastructure.PingProperties
|
||||
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker
|
||||
import org.slf4j.LoggerFactory
|
||||
@@ -20,7 +21,7 @@ import kotlin.uuid.ExperimentalUuidApi
|
||||
*/
|
||||
@RestController
|
||||
@OptIn(ExperimentalUuidApi::class)
|
||||
class PingController(
|
||||
open class PingController(
|
||||
private val pingUseCase: PingUseCase,
|
||||
private val properties: PingProperties
|
||||
) : PingApi {
|
||||
@@ -43,10 +44,16 @@ class PingController(
|
||||
override suspend fun enhancedPing(
|
||||
@RequestParam(required = false, defaultValue = "false") simulate: Boolean
|
||||
): EnhancedPingResponse {
|
||||
logger.info("Enhanced ping requested, simulate: {}", simulate)
|
||||
val start = System.nanoTime()
|
||||
|
||||
if (simulate && Random.nextDouble() < 0.6) {
|
||||
throw RuntimeException("Simulated service failure")
|
||||
if (simulate) {
|
||||
if (Random.nextDouble() < 0.6) {
|
||||
logger.info("Simulating service failure now...")
|
||||
throw SimulatedException("Simulated service failure")
|
||||
} else {
|
||||
logger.info("Simulation mode ACTIVE, but this time lucky: Request passed!")
|
||||
}
|
||||
}
|
||||
|
||||
val domainPing = pingUseCase.executePing("Enhanced Ping")
|
||||
@@ -61,6 +68,8 @@ class PingController(
|
||||
)
|
||||
}
|
||||
|
||||
class SimulatedException(message: String) : RuntimeException(message)
|
||||
|
||||
// Neue Endpunkte
|
||||
|
||||
@GetMapping("/ping/public")
|
||||
@@ -70,7 +79,7 @@ class PingController(
|
||||
}
|
||||
|
||||
@GetMapping("/ping/secure")
|
||||
@PreAuthorize("hasRole('MELD_USER') or hasRole('MELD_ADMIN')") // Beispiel-Rollen
|
||||
@PreAuthorize("hasRole('ROLE_MELD_USER') or hasRole('ROLE_MELD_ADMIN')") // Beispiel-Rollen
|
||||
override suspend fun securePing(): PingResponse {
|
||||
val domainPing = pingUseCase.executePing("Secure Ping")
|
||||
return createResponse(domainPing, "secure-pong")
|
||||
@@ -79,7 +88,7 @@ class PingController(
|
||||
@GetMapping("/ping/sync")
|
||||
override suspend fun syncPings(
|
||||
// Changed the parameter name to 'since' to match SyncManager convention
|
||||
@RequestParam(required = false, defaultValue = "0") since: Long
|
||||
@RequestParam(name = "lastSyncTimestamp", required = false, defaultValue = "0") since: Long
|
||||
): List<PingEvent> {
|
||||
return pingUseCase.getPingsSince(since).map {
|
||||
PingEvent(
|
||||
@@ -91,7 +100,7 @@ class PingController(
|
||||
}
|
||||
|
||||
// Helper
|
||||
private fun createResponse(domainPing: at.mocode.ping.domain.Ping, status: String) = PingResponse(
|
||||
private fun createResponse(domainPing: Ping, status: String) = PingResponse(
|
||||
status = status,
|
||||
timestamp = domainPing.timestamp.atOffset(ZoneOffset.UTC).format(formatter),
|
||||
service = properties.serviceName
|
||||
@@ -99,8 +108,8 @@ class PingController(
|
||||
|
||||
// Fallback
|
||||
@Suppress("unused", "UNUSED_PARAMETER")
|
||||
fun fallbackPing(simulate: Boolean, ex: Exception): EnhancedPingResponse {
|
||||
logger.warn("Circuit breaker fallback triggered: {}", ex.message)
|
||||
open fun fallbackPing(simulate: Boolean, ex: Throwable): EnhancedPingResponse {
|
||||
logger.error("CIRCUIT BREAKER FALLBACK TRIGGERED! Reason: {}", ex.message, ex)
|
||||
return EnhancedPingResponse(
|
||||
status = "fallback",
|
||||
timestamp = java.time.OffsetDateTime.now().format(formatter),
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package at.mocode.ping.infrastructure.web
|
||||
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.ProblemDetail
|
||||
import org.springframework.security.access.AccessDeniedException
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice
|
||||
|
||||
@RestControllerAdvice
|
||||
class PingExceptionHandler {
|
||||
private val log = LoggerFactory.getLogger(PingExceptionHandler::class.java)
|
||||
|
||||
@ExceptionHandler(AccessDeniedException::class)
|
||||
fun handleAccessDenied(ex: AccessDeniedException): ProblemDetail {
|
||||
log.warn("Zugriff verweigert: ${ex.message}")
|
||||
return ProblemDetail.forStatusAndDetail(HttpStatus.FORBIDDEN, "Nicht berechtigt: ${ex.message}")
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception::class)
|
||||
fun handleAll(ex: Exception): ProblemDetail {
|
||||
log.error("Unerwarteter Fehler: ", ex)
|
||||
return ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, ex.message ?: "Ein interner Fehler ist aufgetreten")
|
||||
}
|
||||
|
||||
@ExceptionHandler(RuntimeException::class)
|
||||
fun handleRuntime(ex: RuntimeException): ProblemDetail {
|
||||
log.error("Interner Fehler: ", ex)
|
||||
return ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, ex.message ?: "Unbekannter Fehler")
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user