Skip to content

Commit

Permalink
Merge branch 'main' into v2
Browse files Browse the repository at this point in the history
  • Loading branch information
bgiori committed Feb 29, 2024
2 parents cab54f5 + 1888914 commit b66e1b7
Show file tree
Hide file tree
Showing 13 changed files with 90 additions and 10 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ jobs:
distribution: 'zulu'
java-version: '8'

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Lint
run: ./gradlew ktlintCheck

Expand Down
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
## [1.2.7](https://github.com/amplitude/experiment-jvm-server/compare/1.2.6...1.2.7) (2024-02-07)


### Bug Fixes

* add serverUrl field to AssignmentConfiguration ([#22](https://github.com/amplitude/experiment-jvm-server/issues/22)) ([eb0b251](https://github.com/amplitude/experiment-jvm-server/commit/eb0b25150563ceb1d3649d932887decc3d6ec2c4))

## [1.2.6](https://github.com/amplitude/experiment-jvm-server/compare/1.2.5...1.2.6) (2024-01-31)


### Bug Fixes

* update OkHttp to 4.12.0 ([#19](https://github.com/amplitude/experiment-jvm-server/issues/19)) ([03db9cf](https://github.com/amplitude/experiment-jvm-server/commit/03db9cf8c97141684ae6edc3fa2d8d73bae050fe))

## [1.2.5](https://github.com/amplitude/experiment-jvm-server/compare/1.2.4...1.2.5) (2024-01-29)


### Bug Fixes

* Improve remote evaluation fetch retry logic ([#17](https://github.com/amplitude/experiment-jvm-server/issues/17)) ([5fe439f](https://github.com/amplitude/experiment-jvm-server/commit/5fe439f6cb4fc9b55ace986105efdd707ebcf676))

## [1.2.4](https://github.com/amplitude/experiment-jvm-server/compare/1.2.3...1.2.4) (2023-11-29)


Expand Down
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ java {
dependencies {
implementation(kotlin("stdlib"))
testImplementation(kotlin("test"))
testImplementation("org.mockito:mockito-core:${Versions.mockito}")
testImplementation("io.mockk:mockk:${Versions.mockk}")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:${Versions.serializationRuntime}")
implementation("com.squareup.okhttp3:okhttp:${Versions.okhttp}")
implementation("com.amplitude:evaluation-core:${Versions.evaluationCore}")
Expand All @@ -30,7 +30,7 @@ dependencies {
// Publishing

group = "com.amplitude"
version = "1.2.4"
version = "1.2.7"

nexusPublishing {
repositories {
Expand Down
4 changes: 2 additions & 2 deletions buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ object Versions {
const val serializationPlugin = "1.8.10"
const val serializationRuntime = "1.4.1"
const val json = "20231013"
const val okhttp = "4.9.3"
const val okhttp = "4.12.0"
const val evaluationCore = "2.0.0-beta.2"
const val amplitudeAnalytics = "1.12.0"
const val mockito = "4.8.1"
const val mockk = "1.13.9"
}
2 changes: 1 addition & 1 deletion src/main/kotlin/Experiment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.amplitude.experiment.util.Logger
import com.amplitude.experiment.util.SystemLogger
import java.util.concurrent.Executors

internal const val LIBRARY_VERSION = "1.2.4"
internal const val LIBRARY_VERSION = "1.2.7"

object Experiment {

Expand Down
1 change: 1 addition & 0 deletions src/main/kotlin/LocalEvaluationClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class LocalEvaluationClient internal constructor(
setEventUploadPeriodMillis(config.assignmentConfiguration.eventUploadPeriodMillis)
useBatchMode(config.assignmentConfiguration.useBatchMode)
setOptions(Options().setMinIdLength(1))
setServerUrl(config.assignmentConfiguration.serverUrl)
},
InMemoryAssignmentFilter(config.assignmentConfiguration.cacheCapacity)
)
Expand Down
1 change: 1 addition & 0 deletions src/main/kotlin/LocalEvaluationConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,5 @@ data class AssignmentConfiguration(
val eventUploadThreshold: Int = 10,
val eventUploadPeriodMillis: Int = 10000,
val useBatchMode: Boolean = true,
val serverUrl: String = "https://api2.amplitude.com/2/httpapi",
)
12 changes: 10 additions & 2 deletions src/main/kotlin/RemoteEvaluationClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.amplitude.experiment

import com.amplitude.experiment.evaluation.EvaluationVariant
import com.amplitude.experiment.util.BackoffConfig
import com.amplitude.experiment.util.FetchException
import com.amplitude.experiment.util.Logger
import com.amplitude.experiment.util.backoff
import com.amplitude.experiment.util.json
Expand Down Expand Up @@ -39,7 +40,7 @@ class RemoteEvaluationClient internal constructor(
fun fetch(user: ExperimentUser): CompletableFuture<Map<String, Variant>> {
return doFetch(user, config.fetchTimeoutMillis).handle { variants, t ->
if (t != null || variants == null) {
if (retry) {
if (retry && shouldRetryFetch(t)) {
backoff(backoffConfig) {
doFetch(user, config.fetchTimeoutMillis)
}
Expand Down Expand Up @@ -86,7 +87,7 @@ class RemoteEvaluationClient internal constructor(
Logger.d("Received fetch response: $response")
val variants = response.use {
if (!response.isSuccessful) {
throw IOException("fetch error response: $response")
throw FetchException(response.code, "fetch error response: $response")
}
parseRemoteResponse(response.body?.string() ?: "")
}
Expand All @@ -108,3 +109,10 @@ internal fun parseRemoteResponse(jsonString: String): Map<String, Variant> =
json.decodeFromString<HashMap<String, EvaluationVariant>>(
jsonString
).mapValues { it.value.toVariant() }

private fun shouldRetryFetch(t: Throwable): Boolean {
if (t is FetchException) {
return t.statusCode < 400 || t.statusCode >= 500 || t.statusCode == 429
}
return true
}
1 change: 0 additions & 1 deletion src/main/kotlin/assignment/AssignmentService.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.amplitude.experiment.assignment

import com.amplitude.Amplitude
import com.amplitude.AmplitudeCallbacks
import com.amplitude.Event
import org.json.JSONObject

Expand Down
8 changes: 8 additions & 0 deletions src/main/kotlin/util/FetchException.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.amplitude.experiment.util

import okio.IOException

internal class FetchException(
val statusCode: Int,
message: String
) : IOException(message)
1 change: 0 additions & 1 deletion src/main/kotlin/util/Request.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.amplitude.experiment.util

import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
Expand Down
1 change: 0 additions & 1 deletion src/test/kotlin/ExperimentUserTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ class ExperimentUserTest {
},
"groups" to buildJsonObject {
put("group", buildJsonArray { add("group") })

},
"group_properties" to buildJsonObject {
put(
Expand Down
39 changes: 39 additions & 0 deletions src/test/kotlin/RemoteEvaluationClientTest.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.amplitude.experiment

import com.amplitude.experiment.util.FetchException
import com.amplitude.experiment.util.Logger
import com.amplitude.experiment.util.SystemLogger
import io.mockk.every
import io.mockk.spyk
import io.mockk.verify
import org.junit.Assert
import java.util.Date
import java.util.concurrent.CancellationException
Expand Down Expand Up @@ -100,6 +104,41 @@ class RemoteEvaluationClientTest {
// }
// }
// }

@Test
fun `fetch retry with different response codes`() {
// Response code, error message, and whether retry should be called
val testData = listOf(
Triple(300, "Fetch Exception 300", 2),
Triple(400, "Fetch Exception 400", 1),
Triple(429, "Fetch Exception 429", 2),
Triple(500, "Fetch Exception 500", 2),
Triple(0, "Other Exception", 2)
)

testData.forEach { (responseCode, errorMessage, fetchCalls) ->
val config = RemoteEvaluationConfig(fetchRetries = 1, debug = true)
val client = spyk(RemoteEvaluationClient("apiKey", config), recordPrivateCalls = true)
// Mock the private method to throw FetchException or other exceptions
every { client["doFetch"](any<ExperimentUser>(), any<Long>()) } answers {
val future = CompletableFuture<Map<String, Variant>>()
if (responseCode == 0) {
future.completeExceptionally(Exception(errorMessage))
} else {
future.completeExceptionally(FetchException(responseCode, errorMessage))
}
future
}

try {
client.fetch(ExperimentUser("test_user")).get()
} catch (t: Throwable) {
// catch exception
}

verify(exactly = fetchCalls) { client["doFetch"](any<ExperimentUser>(), any<Long>()) }
}
}
}

@Suppress("SameParameterValue")
Expand Down

0 comments on commit b66e1b7

Please sign in to comment.