add Redis cache and some clean up

- update and cleanup in README.md
- update getIdentity to throw response exception with 401 in JwtService
- update http files to use identity from env
- add cacheable to getIdentityFromDevice in DeviceRegistryService
- add RedisCacheConfiguration
- add CacheProperty
- set up cache property
- set up data redis cache
This commit is contained in:
2024-12-24 05:50:56 +01:00
parent 19f46bd01f
commit 6522809dce
14 changed files with 153 additions and 62 deletions

View File

@@ -1,5 +1,6 @@
package ltd.hlaeja
import ltd.hlaeja.property.CacheProperty
import ltd.hlaeja.property.DeviceConfigurationProperty
import ltd.hlaeja.property.DeviceDataProperty
import ltd.hlaeja.property.DeviceRegistryProperty
@@ -7,8 +8,11 @@ import ltd.hlaeja.property.JwtProperty
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.runApplication
import org.springframework.cache.annotation.EnableCaching
@EnableCaching
@EnableConfigurationProperties(
CacheProperty::class,
DeviceConfigurationProperty::class,
DeviceDataProperty::class,
DeviceRegistryProperty::class,

View File

@@ -0,0 +1,26 @@
package ltd.hlaeja.configuration
import java.time.Duration
import ltd.hlaeja.exception.CacheException
import ltd.hlaeja.property.CacheProperty
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.redis.cache.RedisCacheConfiguration
import org.springframework.data.redis.cache.RedisCacheManager
import org.springframework.data.redis.core.RedisTemplate
@Configuration
class RedisCacheConfiguration(
private val cacheProperty: CacheProperty,
) {
@Bean
fun cacheManager(
redisTemplate: RedisTemplate<String, String>,
): RedisCacheManager = redisTemplate.connectionFactory
?.let { RedisCacheManager.builder(it).cacheDefaults(getRedisCacheConfiguration()).build() }
?: throw CacheException("Redis connection factory is not set")
private fun getRedisCacheConfiguration(): RedisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(cacheProperty.timeToLive))
}

View File

@@ -0,0 +1,23 @@
package ltd.hlaeja.exception
@Suppress("unused")
class CacheException : Exception {
constructor() : super()
constructor(message: String) : super(message)
constructor(cause: Throwable) : super(cause)
constructor(
message: String,
cause: Throwable,
) : super(message, cause)
constructor(
message: String,
cause: Throwable,
enableSuppression: Boolean,
writableStackTrace: Boolean,
) : super(message, cause, enableSuppression, writableStackTrace)
}

View File

@@ -0,0 +1,8 @@
package ltd.hlaeja.property
import org.springframework.boot.context.properties.ConfigurationProperties
@ConfigurationProperties(prefix = "cache")
data class CacheProperty(
val timeToLive: Long,
)

View File

@@ -7,6 +7,7 @@ import java.util.UUID
import ltd.hlaeja.library.deviceRegistry.Identity
import ltd.hlaeja.property.DeviceRegistryProperty
import ltd.hlaeja.util.deviceRegistryIdentityDevice
import org.springframework.cache.annotation.Cacheable
import org.springframework.http.HttpStatus.SERVICE_UNAVAILABLE
import org.springframework.stereotype.Service
import org.springframework.web.ErrorResponseException
@@ -31,6 +32,7 @@ class DeviceRegistryService(
.description("Number of failed device identity calls")
.register(meterRegistry)
@Cacheable(value = ["identity"], key = "#device")
suspend fun getIdentityFromDevice(
device: UUID,
): Identity.Response = try {

View File

@@ -1,13 +1,16 @@
package ltd.hlaeja.service
import io.github.oshai.kotlinlogging.KotlinLogging
import io.jsonwebtoken.JwtException
import io.jsonwebtoken.JwtParser
import io.jsonwebtoken.Jwts
import java.util.UUID
import ltd.hlaeja.library.deviceRegistry.Identity
import ltd.hlaeja.property.JwtProperty
import ltd.hlaeja.util.PublicKeyProvider
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Service
import org.springframework.web.server.ResponseStatusException
private val log = KotlinLogging.logger {}
@@ -23,8 +26,13 @@ class JwtService(
suspend fun getIdentity(
identityToken: String,
): Identity.Response = readIdentity(identityToken)
.let { deviceRegistry.getIdentityFromDevice(it) }
): Identity.Response = try {
readIdentity(identityToken)
.let { deviceRegistry.getIdentityFromDevice(it) }
} catch (e: JwtException) {
log.warn { e.localizedMessage }
throw ResponseStatusException(HttpStatus.UNAUTHORIZED)
}
private suspend fun readIdentity(
identity: String,

View File

@@ -39,6 +39,11 @@
"name": "device-configuration.url",
"type": "java.lang.String",
"description": "Url for device configuration service."
},
{
"name": "cache.time-to-live",
"type": "java.lang.Long",
"description": "Cache expiration in minutes."
}
]
}

View File

@@ -9,6 +9,12 @@ spring:
os:
name: "%APP_BUILD_OS_NAME%"
version: "%APP_BUILD_OS_VERSION%"
cache:
type: redis
data:
redis:
port: 6379
database: 1
management:
endpoints:
@@ -29,6 +35,9 @@ management:
bucket: hlaeja
org: hlaeja_ltd
cache:
time-to-live: 10
jwt:
public-key: cert/public_key.pem
@@ -40,6 +49,9 @@ spring:
config:
activate:
on-profile: development
data:
redis:
host: localhost
management:
metrics:
@@ -76,6 +88,9 @@ spring:
config:
activate:
on-profile: docker
data:
redis:
host: Redis
management:
metrics:

View File

@@ -6,3 +6,5 @@ device-data:
url: http://localhost:9020
device-configuration:
url: http://localhost:9030
cache:
time-to-live: 10