Skip to content

Commit 1cb22ec

Browse files
committed
Add caching for -attributes endpoints
1 parent 055f0a1 commit 1cb22ec

File tree

4 files changed

+79
-9
lines changed

4 files changed

+79
-9
lines changed

gradle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
org.gradle.jvmargs=-Xmx5g
12
org.gradle.caching=true
23
# Must be later than 2022.1
34
gradle.enterprise.version=2022.4

src/main/kotlin/com/gabrielfeo/gradle/enterprise/api/Api.kt

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package com.gabrielfeo.gradle.enterprise.api
55
import com.gabrielfeo.gradle.enterprise.api.auth.HttpBearerAuth
66
import com.gabrielfeo.gradle.enterprise.api.infrastructure.Serializer
77
import okhttp3.OkHttpClient
8-
import okhttp3.logging.HttpLoggingInterceptor
98
import retrofit2.Retrofit
109
import retrofit2.converter.moshi.MoshiConverterFactory
1110
import retrofit2.converter.scalars.ScalarsConverterFactory
@@ -14,19 +13,25 @@ import kotlin.time.Duration.Companion.seconds
1413

1514
var baseUrl: () -> String = { requireBaseUrl() }
1615
var accessToken: () -> String = { requireToken() }
16+
1717
var maxConcurrentRequests = 30
18+
var maxCacheSize = 500_000_000L
19+
20+
val cacheablePaths: MutableList<Regex> = mutableListOf(
21+
""".*/api/builds/[\d\w]+/(?:gradle|maven)-attributes""".toRegex(),
22+
)
1823

1924
val okHttpClient: OkHttpClient by lazy {
2025
OkHttpClient.Builder()
26+
.cache(cache)
2127
.addInterceptor(HttpBearerAuth("bearer", accessToken()))
22-
.addInterceptor(HttpLoggingInterceptor())
28+
.addInterceptor(CacheHitLoggingInterceptor())
29+
.addNetworkInterceptor(CacheEnforcingInterceptor(cacheablePaths))
2330
.build()
2431
.apply {
2532
dispatcher.maxRequests = maxConcurrentRequests
2633
dispatcher.maxRequestsPerHost = maxConcurrentRequests
27-
if (_debugLoggingEnabled) {
28-
logRequestCountEvery(2.seconds)
29-
}
34+
startRequestCountLogging(this, period = 2.seconds)
3035
}
3136
}
3237

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.gabrielfeo.gradle.enterprise.api
2+
3+
import okhttp3.*
4+
import okhttp3.HttpUrl.Companion.toHttpUrl
5+
import java.io.File
6+
import kotlin.time.Duration.Companion.days
7+
8+
internal val cache: Cache = run {
9+
val host = baseUrl().toHttpUrl().host
10+
val tempDir = System.getProperty("java.io.tmpdir")
11+
Cache(
12+
directory = File(tempDir, "gradle-enterprise-api-cache-$host"),
13+
maxSize = maxCacheSize,
14+
)
15+
}
16+
17+
internal class CacheEnforcingInterceptor(
18+
private val cacheablePaths: List<Regex>,
19+
) : Interceptor {
20+
21+
private val maxAge = 365.days.inWholeMilliseconds
22+
23+
override fun intercept(chain: Interceptor.Chain): Response {
24+
val request = chain.request()
25+
if (!isCacheable(request)) {
26+
return chain.proceed(request)
27+
}
28+
val response = chain.proceed(request)
29+
return response.newBuilder()
30+
.header("cache-control", "max-age=$maxAge")
31+
.removeHeader("pragma")
32+
.removeHeader("expires")
33+
.removeHeader("vary")
34+
.build()
35+
}
36+
37+
private fun isCacheable(request: Request) =
38+
cacheablePaths.any { it.matches(request.url.toString()) }
39+
}

src/main/kotlin/com/gabrielfeo/gradle/enterprise/api/DebugLogging.kt

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,45 @@ import kotlinx.coroutines.DelicateCoroutinesApi
44
import kotlinx.coroutines.GlobalScope
55
import kotlinx.coroutines.delay
66
import kotlinx.coroutines.launch
7+
import okhttp3.Interceptor
78
import okhttp3.OkHttpClient
9+
import okhttp3.Response
810
import java.util.logging.Level.INFO
911
import java.util.logging.Logger
1012
import kotlin.time.Duration
1113

1214
@Suppress("ObjectPropertyName")
1315
var _debugLoggingEnabled = System.getenv("GRADLE_ENTERPRISE_API_DEBUG_LOGGING").toBoolean()
1416

17+
internal class CacheHitLoggingInterceptor(
18+
private val logger: Logger = Logger.getGlobal(),
19+
) : Interceptor {
20+
21+
override fun intercept(chain: Interceptor.Chain): Response {
22+
if (!_debugLoggingEnabled) {
23+
return chain.proceed(chain.request())
24+
}
25+
val url = chain.request().url
26+
val response = chain.proceed(chain.request())
27+
val wasHit = with(response) { cacheResponse != null && networkResponse == null }
28+
val hitOrMiss = if (wasHit) "hit" else "miss"
29+
logger.log(INFO, "Cache $hitOrMiss: $url")
30+
return response
31+
}
32+
}
33+
1534
@OptIn(DelicateCoroutinesApi::class)
16-
internal fun OkHttpClient.logRequestCountEvery(period: Duration) {
35+
internal fun startRequestCountLogging(
36+
client: OkHttpClient,
37+
period: Duration,
38+
logger: Logger = Logger.getGlobal(),
39+
) {
40+
if (!_debugLoggingEnabled) {
41+
return
42+
}
1743
GlobalScope.launch {
18-
val logger = Logger.getGlobal()
19-
while (!dispatcher.executorService.isShutdown) {
20-
val count = dispatcher.runningCallsCount()
44+
while (!client.dispatcher.executorService.isShutdown) {
45+
val count = client.dispatcher.runningCallsCount()
2146
logger.log(INFO, "$count requests running")
2247
delay(period)
2348
}

0 commit comments

Comments
 (0)