Skip to content

Commit cdeafb9

Browse files
committed
Configure allowed number of years back, whether or not to include current year, and initialize sleepingpill cache at startup
1 parent f9c97ec commit cdeafb9

File tree

6 files changed

+51
-27
lines changed

6 files changed

+51
-27
lines changed

backend/src/main/kotlin/no/java/cupcake/Application.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ private fun Application.sleepingPillService(bringService: BringService): Sleepin
6666
client = sleepingPillClient(config),
6767
bringService = bringService,
6868
cacheTimeoutSeconds = config.cacheTtlSeconds,
69+
maxPastYears = config.maxPastYears,
70+
includeCurrentYear = config.includeCurrentYear,
6971
)
7072
}
7173

backend/src/main/kotlin/no/java/cupcake/config/SleepingPillConfig.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@ data class SleepingPillConfig(
55
val password: String,
66
val rootUrl: String,
77
val cacheTtlSeconds: Long,
8+
val maxPastYears: Long = 3,
9+
val includeCurrentYear: Boolean = false
810
)

backend/src/main/kotlin/no/java/cupcake/sleepingpill/Conference.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import arrow.core.raise.either
44
import arrow.core.raise.ensure
55
import kotlinx.serialization.Serializable
66
import no.java.cupcake.api.ConferenceIdRequired
7+
import java.time.Year
78

89
@Serializable
910
data class Conference(
@@ -18,7 +19,9 @@ data class SleepingPillConference(
1819
val slug: String,
1920
val id: String,
2021
val slottimes: String?,
21-
)
22+
) {
23+
val year: Year get() = Year.of(name.substringAfterLast(" ").toInt())
24+
}
2225

2326
@Serializable
2427
data class SleepingPillConferences(

backend/src/main/kotlin/no/java/cupcake/sleepingpill/SleepingPillService.kt

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ import kotlinx.coroutines.SupervisorJob
1919
import kotlinx.coroutines.async
2020
import kotlinx.coroutines.future.asCompletableFuture
2121
import kotlinx.coroutines.future.await
22+
import kotlinx.coroutines.runBlocking
2223
import no.java.cupcake.api.ApiError
2324
import no.java.cupcake.api.ErrorResponse
2425
import no.java.cupcake.api.SleepingPillCallFailed
2526
import no.java.cupcake.bring.BringService
2627
import java.time.Duration
28+
import java.time.Year
2729

2830
private val logger = KotlinLogging.logger {}
2931

@@ -36,37 +38,45 @@ class SleepingPillService(
3638
private val bringService: BringService,
3739
cacheTimeoutSeconds: Long,
3840
private val cacheScope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO),
41+
private val maxPastYears: Long,
42+
private val includeCurrentYear: Boolean,
3943
) {
40-
private val ttl: Duration =
41-
if (cacheTimeoutSeconds <= 0) Duration.ZERO else Duration.ofSeconds(cacheTimeoutSeconds)
44+
private val ttl: Duration = if (cacheTimeoutSeconds <= 0) Duration.ZERO else Duration.ofSeconds(cacheTimeoutSeconds)
4245

4346
private val conferencesCache: AsyncLoadingCache<String, List<Conference>> =
44-
Caffeine
45-
.newBuilder()
46-
.apply { if (!ttl.isZero) expireAfterWrite(ttl) }
47-
.buildAsync { _, _ ->
48-
cacheScope
49-
.async {
50-
uncachedConferencesEither().fold(
51-
ifLeft = { throw ApiErrorException(it) },
52-
ifRight = { it },
53-
)
54-
}.asCompletableFuture()
55-
}
47+
Caffeine.newBuilder().apply { if (!ttl.isZero) expireAfterWrite(ttl) }.buildAsync { _, _ ->
48+
cacheScope
49+
.async {
50+
uncachedConferencesEither().fold(
51+
ifLeft = { throw ApiErrorException(it) },
52+
ifRight = { it },
53+
)
54+
}.asCompletableFuture()
55+
}
5656

5757
private val sessionsCache: AsyncLoadingCache<ConferenceId, List<Session>> =
58-
Caffeine
59-
.newBuilder()
60-
.apply { if (!ttl.isZero) expireAfterWrite(ttl) }
61-
.buildAsync { id, _ ->
62-
cacheScope
63-
.async {
64-
uncachedSessionsEither(id).fold(
65-
ifLeft = { throw ApiErrorException(it) },
66-
ifRight = { it },
67-
)
68-
}.asCompletableFuture()
58+
Caffeine.newBuilder().apply { if (!ttl.isZero) expireAfterWrite(ttl) }.buildAsync { id, _ ->
59+
cacheScope
60+
.async {
61+
uncachedSessionsEither(id).fold(
62+
ifLeft = { throw ApiErrorException(it) },
63+
ifRight = { it },
64+
)
65+
}.asCompletableFuture()
66+
}
67+
68+
init {
69+
runBlocking {
70+
either {
71+
val conferences = conferences()
72+
conferences.forEach { conference ->
73+
sessions(ConferenceId(conference.id).bind())
74+
}
75+
}.onLeft { error ->
76+
logger.warn { "Failed to initialize conferences cache: $error" }
6977
}
78+
}
79+
}
7080

7181
private suspend fun uncachedConferencesEither(): Either<ApiError, List<Conference>> =
7282
either {
@@ -76,7 +86,10 @@ class SleepingPillService(
7686
.body<SleepingPillConferences>()
7787
.conferences
7888
.filterNot { rejectSlugs.contains(it.slug) }
79-
.map {
89+
.filter {
90+
val now = Year.now()
91+
it.year.isAfter(now.minusYears(maxPastYears + 1)) && (includeCurrentYear || it.year.isBefore(now))
92+
}.map {
8093
Conference(
8194
name = it.name,
8295
slug = it.slug,

backend/src/main/resources/application.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ sleepingpill {
3131
password = ${?SP_PASSWORD}
3232
cache_ttl_seconds = 3600
3333
cache_ttl_seconds = ${?SP_CACHE_TTL_SECONDS}
34+
max_past_years = 3
35+
include_current_year = true
3436
}
3537

3638
bring {

backend/src/test/kotlin/no/java/cupcake/TestExtensions.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ fun buildSleepingPillService(
101101
client = client ?: buildClient(buildMockEngine(fixture, block)),
102102
bringService = bringService ?: buildBringService(fixture = "/postal_codes.json", postalCodeUrl = "/test"),
103103
cacheTimeoutSeconds = 10,
104+
maxPastYears = 3,
105+
includeCurrentYear = true,
104106
)
105107

106108
fun buildBringService(

0 commit comments

Comments
 (0)