Skip to content

Commit d9bf72f

Browse files
committed
get rid of caching profile, use the value of spring.cache.type instead.
1 parent ab69ce2 commit d9bf72f

14 files changed

Lines changed: 83 additions & 76 deletions

File tree

README.md

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -152,41 +152,43 @@ The application needs to fetch the metadata associated to an object (and a token
152152
To speed it up, the application can be configured to cache those metadata using either an in-memory concurrent hashmap,
153153
or an external database such as redis.
154154

155-
**To enable caching**, set the `caching` active profile. It will use in-memory caching by default (`simple`).
156-
To use another caching strategy, use the property `spring.cache.type=redis|simple|none` (none = no cache).
157-
Note that `none` doesn't disable caching, just ensures nothing is actually put into the cache.
155+
**To enable/disable caching**, set the `spring.cache.type` property. The former can take three values:
156+
157+
* `none`: value by default, no caching at all,
158+
* `simple`: in-memory caching, only possible when the application runs in standalone mode, with both input and output enabled,
159+
* `redis`: use a redis instance for caching; this is mandatory if you want to deploy input and output separately and still use a cache.
160+
158161
Example:
159162
```
160-
./bbdata-api-*.jar --spring.profiles.active=caching
163+
./bbdata-api-*.jar --spring.cache.type=simple
161164
```
162165

163-
164-
Redis default properties are shown below (can be overriden from a property file). To use redis, activate the `caching` profile
165-
and set `spring.cache.type=redis`:
166+
Redis default properties are shown below (can be overriden from a property file). When using `spring.cache.type=redis`,
167+
you can override any of those properties to point to your redis server instance:
166168

167169
```properties
168-
# To actually use redis cache, enable caching through the caching profile and uncomment this line:
169-
#spring.cache.type=redis
170+
# Relevant properties in order to use redis (localhost and 6379 are the default)
171+
spring.cache.type=redis
170172
spring.redis.host=localhost
171173
spring.redis.port=6379
172174
```
173175

174-
By default, the cache logger is set to `TRACE`. This can be problematic in production, so feel free to turn it off using:
176+
By default, the cache logger is set to `INFO`. Feel free to change it using:
175177
```properties
176-
# default to TRACE
177-
logging.level.org.springframework.cache=WARN
178+
# default to INFO
179+
logging.level.org.springframework.cache=TRACE
178180
```
179181

180-
If caching is enabled, a hidden endpoint is available in order to clear all cache entries: `GET /cache-evict`.
182+
When caching is enabled, a hidden endpoint is available in order to clear all cache entries: `GET /cache-evict`.
181183
In order to avoid having folks discover this endpoint and play with it, you can configure a secret key to use via the property:
182-
```
184+
```properties
183185
cache.evict.secret-key=XXX
184186
```
185187
If this property is defined, you will have to use `GET /cache-evict?key=XXX` for the eviction to be performed.
186188

187189

188190
**IMPORTANT**: in case you deploy the input api and the output api separately (using profiles),
189-
YOU NEED TO USE AN EXTERNAL CACHE (e.g. redis). This is because the output API is responsible for evicting old entries
191+
YOU NEED TO USE AN EXTERNAL CACHE (i.e. redis). This is because the output API is responsible for evicting old entries
190192
from the cache. If the input and the output do not run in the same JVM, the cache strategy `simple` is *dangerous*:
191193
the input api won't see if a token gets deleted, or if an object becomes disabled.
192194

src/main/kotlin/ch/derlin/bbdata/BBDataApplication.kt

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package ch.derlin.bbdata
22

3+
import ch.derlin.bbdata.common.OnCacheEnabled
34
import ch.derlin.bbdata.common.dates.JodaUtils
45
import io.swagger.v3.oas.annotations.OpenAPIDefinition
56
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType
@@ -83,9 +84,9 @@ class CassandraConfig
8384

8485
// @EnableCaching adds many layers of AOP/interceptor, even if spring.cache.type=none
8586
// Hence, we only enable it if explicitly asked.
86-
// see https://stackoverflow.com/a/56901878
87+
// see @OnCacheEnabled and https://stackoverflow.com/a/56901878
8788
@Configuration
88-
@Profile(Profiles.CACHING)
89+
@OnCacheEnabled
8990
@EnableCaching
9091
class CachingConfig {
9192

@@ -99,11 +100,8 @@ class CachingConfig {
99100

100101
@PostConstruct
101102
fun checkCacheType() {
102-
if (cacheType.toLowerCase() == "none") {
103-
// ensure some caching mechanism is set, or generate an error in the log
104-
logger.error("${Profiles.CACHING} is set, but cache type is none. This create unnecessary overhead. " +
105-
"Either disable caching or set spring.cache.type=simple.")
106-
} else if (cacheType.toLowerCase() == "simple" &&
103+
logger.info("caching ENABLED")
104+
if (cacheType.toLowerCase() == "simple" &&
107105
(environment.activeProfiles.contains(Profiles.INPUT_ONLY) || environment.activeProfiles.contains(Profiles.OUTPUT_ONLY))) {
108106
// forbid in-memory caching if launching the app in split mode (input only or output only)
109107
logger.error("Using in-memory caching with split application (input|output in different JVMs) can lead to security issues." +
@@ -113,7 +111,6 @@ class CachingConfig {
113111
}
114112
}
115113

116-
117114
fun main(args: Array<String>) {
118115
runApplication<BBDataApplication>(*args)
119116
}

src/main/kotlin/ch/derlin/bbdata/CustomProperties.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,15 @@ object HiddenEnvironmentVariables {
1414

1515
/** boolean to turn off kafka */
1616
const val NO_KAFKA = "BB_NO_KAFKA"
17+
1718
/** integer to override the default user when the unsecured profile is used */
1819
const val UNSECURED_USER = "UNSECURED_BBUSER"
1920
}
2021

22+
object Constants {
23+
const val META_CACHE = "metas"
24+
}
25+
2126
@Configuration
2227
@ConfigurationProperties(prefix = "scan")
2328
class ScanExcludeProperties {
@@ -43,7 +48,8 @@ class AsyncProperties {
4348

4449
@Configuration
4550
@ConfigurationProperties(prefix = "cache.evict")
46-
class CacheProperties {
51+
class CacheEvictProperties {
52+
4753
/** Optional secret key to call cache evict: see CacheEvictController */
4854
var secretKey: String = ""
4955

src/main/kotlin/ch/derlin/bbdata/Excluders.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class ExcludeAutoConfigPostProcessor : EnvironmentPostProcessor {
5050

5151
val excludes = env.getPrefixedProperties(PROP)
5252
// also exclude Redis AutoConfiguration unless the caching profile is enabled and redis is selected
53-
if (!(env.activeProfiles.contains("caching") && env.getProperty("spring.cache.type") == "redis"))
53+
if (env.getProperty("spring.cache.type") != "redis")
5454
excludes.add(RedisAutoConfiguration::class.qualifiedName!!)
5555
// override $PROP
5656
env.propertySources.addFirst(MapPropertySource(PROP, mapOf(PROP to excludes)))

src/main/kotlin/ch/derlin/bbdata/Profiles.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,4 @@ object Profiles {
2626
// where do you store statistics about objects
2727
const val SQL_STATS = "sqlstats"
2828
const val CASSANDRA_STATS = "!$SQL_STATS"
29-
30-
// optionally enable caching
31-
const val CACHING = "caching"
3229
}

src/main/kotlin/ch/derlin/bbdata/common/CacheConstants.kt

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package ch.derlin.bbdata.common
2+
3+
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression
4+
5+
/**
6+
* This annotation can be used to only enable a component or configuration is the
7+
* spring.cache.type property is set (i.e. not none).
8+
* example:
9+
*
10+
* ```
11+
* @Configuration
12+
* @CachingEnabled
13+
* @EnableCaching
14+
* class CacheConfig {
15+
* /** enable caching only if spring.cache.type specified */
16+
* }
17+
* ```
18+
*
19+
* date: 14.09.20
20+
* @author Lucy Linder <lucy.derlin@gmail.com>
21+
*/
22+
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
23+
@kotlin.annotation.Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
24+
@ConditionalOnExpression("'\${spring.cache.type:none}' != 'none'")
25+
annotation class OnCacheEnabled

src/main/kotlin/ch/derlin/bbdata/input/InputRepository.kt

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package ch.derlin.bbdata.input
22

3-
import ch.derlin.bbdata.common.CacheConstants
4-
import org.springframework.beans.factory.annotation.Autowired
3+
import ch.derlin.bbdata.Constants
54
import org.springframework.cache.annotation.Cacheable
65
import org.springframework.stereotype.Component
76
import java.io.Serializable
@@ -15,7 +14,7 @@ import javax.persistence.EntityManager
1514

1615

1716
@Component
18-
class InputRepository {
17+
class InputRepository(private val em: EntityManager) {
1918

2019
class MeasureMeta(fields: Array<Any>) : Serializable {
2120
val unitName: String = fields[0] as String
@@ -33,11 +32,7 @@ class InputRepository {
3332
}
3433
}
3534

36-
37-
@Autowired
38-
private lateinit var em: EntityManager
39-
40-
@Cacheable(CacheConstants.CACHE_NAME, key = "#objectId.toString().concat(':').concat(#token)", unless = "#result == null")
35+
@Cacheable(Constants.META_CACHE, key = "#objectId.toString().concat(':').concat(#token)", unless = "#result == null")
4136
fun getMeasureMeta(objectId: Long, token: String): Optional<MeasureMeta> {
4237
val query = em.createNativeQuery(MeasureMeta.NATIVE_QUERY)
4338

src/main/kotlin/ch/derlin/bbdata/output/CacheEvictController.kt

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
package ch.derlin.bbdata.output
22

3-
import ch.derlin.bbdata.CacheProperties
4-
import ch.derlin.bbdata.Profiles
5-
import ch.derlin.bbdata.common.CacheConstants
3+
import ch.derlin.bbdata.CacheEvictProperties
4+
import ch.derlin.bbdata.Constants
5+
import ch.derlin.bbdata.common.OnCacheEnabled
66
import ch.derlin.bbdata.common.exceptions.ForbiddenException
77
import ch.derlin.bbdata.output.api.CommonResponses
88
import io.swagger.v3.oas.annotations.Hidden
99
import org.springframework.cache.CacheManager
10-
import org.springframework.context.annotation.Profile
1110
import org.springframework.http.ResponseEntity
1211
import org.springframework.web.bind.annotation.GetMapping
1312
import org.springframework.web.bind.annotation.RequestParam
@@ -18,16 +17,16 @@ import org.springframework.web.bind.annotation.RestController
1817
* @author Lucy Linder <lucy.derlin@gmail.com>
1918
*/
2019
@RestController
21-
@Profile(Profiles.CACHING)
20+
@OnCacheEnabled
2221
class CacheEvictController(
23-
private val cacheProperties: CacheProperties,
22+
private val cacheEvictProperties: CacheEvictProperties,
2423
private val cacheManager: CacheManager) {
2524

2625
@Hidden
2726
@GetMapping("/cache-evict")
2827
fun cacheEvict(@RequestParam("key", required = false) key: String?): ResponseEntity<String> {
29-
if (cacheProperties.matches(key)) {
30-
cacheManager.getCache(CacheConstants.CACHE_NAME)?.clear()
28+
if (cacheEvictProperties.matches(key)) {
29+
cacheManager.getCache(Constants.META_CACHE)?.clear()
3130
return CommonResponses.ok("Cache evicted.")
3231
} else {
3332
throw ForbiddenException("This endpoint is not available.")

src/main/kotlin/ch/derlin/bbdata/output/api/objects/ObjectsController.kt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@ package ch.derlin.bbdata.output.api.objects
55
* @author Lucy Linder <lucy.derlin@gmail.com>
66
*/
77

8-
import ch.derlin.bbdata.common.Beans
9-
import ch.derlin.bbdata.common.CacheConstants
10-
import ch.derlin.bbdata.common.HiddenParam
11-
import ch.derlin.bbdata.common.PageableAsQueryParam
8+
import ch.derlin.bbdata.Constants
9+
import ch.derlin.bbdata.common.*
1210
import ch.derlin.bbdata.common.exceptions.ItemNotFoundException
1311
import ch.derlin.bbdata.common.exceptions.WrongParamsException
1412
import ch.derlin.bbdata.output.api.CommonResponses
@@ -215,9 +213,9 @@ class ObjectsController(private val objectsAccessManager: ObjectsAccessManager,
215213

216214
@Protected(SecurityConstants.SCOPE_WRITE)
217215
@Operation(description = "Enable an object you own. If the object is already enabled, it simply returns NOT MODIFIED.")
216+
@CacheEvict(Constants.META_CACHE, allEntries = true)
218217
@SimpleModificationStatusResponse
219218
@PostMapping("{objectId}/enable")
220-
@CacheEvict(CacheConstants.CACHE_NAME, allEntries = true) // TODO: find a better way
221219
fun enableObject(
222220
@UserId userId: Int,
223221
@PathVariable(value = "objectId") id: Long): ResponseEntity<String> =
@@ -226,9 +224,9 @@ class ObjectsController(private val objectsAccessManager: ObjectsAccessManager,
226224
@Protected(SecurityConstants.SCOPE_WRITE)
227225
@Operation(description = "Disable an object you own. If the object is already disabled, it simply returns NOT MODIFIED. " +
228226
"When an object gets disabled, all its tokens are deleted and it cannot receive new values (no new measures).")
227+
@CacheEvict(Constants.META_CACHE, allEntries = true)
229228
@SimpleModificationStatusResponse
230229
@PostMapping("{objectId}/disable")
231-
@CacheEvict(CacheConstants.CACHE_NAME, allEntries = true) // TODO: find a better way
232230
fun disableObject(
233231
@UserId userId: Int,
234232
@PathVariable(value = "objectId") id: Long): ResponseEntity<String> =

0 commit comments

Comments
 (0)