Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: auto deployment mgmt; group cohorts; v2 evaluation #13

Merged
merged 20 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,9 @@ The default location for the configuration yaml file is `/etc/evaluation-proxy-c

```yaml
projects:
- id: "YOUR PROJECT ID"
apiKey: "YOUR API KEY"
secretKey: " YOUR SECRET KEY"
deploymentKeys:
- "YOUR DEPLOYMENT KEY 1"
- "YOUR DEPLOYMENT KEY 2"
- apiKey: "YOUR API KEY"
secretKey: "YOUR SECRET KEY"
managementKey: "YOUR MANAGEMENT API KEY"

configuration:
redis:
Expand All @@ -43,7 +40,7 @@ Use the evaluation proxy [Helm chart](https://github.com/amplitude/evaluation-pr

### Docker Compose Example

Run the container locally with redis persistence using `docker compose`. You must first update the `compose-config.yaml` file with your project and deployment keys before running the composition.
Run the container locally with redis persistence using `docker compose`. You must first update the `compose-config.yaml` file with your project keys before running the composition.

```
docker compose build
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
kotlin("jvm") version "1.8.10"
kotlin("jvm") version "1.9.10"
id("io.github.gradle-nexus.publish-plugin") version "1.1.0"
}

Expand Down
6 changes: 2 additions & 4 deletions compose-config.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
projects:
- id: "TODO"
apiKey: "TODO"
- apiKey: "TODO"
secretKey: "TODO"
deploymentKeys:
- "TODO"
managementKey: "TODO"

configuration:
redis:
Expand Down
7 changes: 3 additions & 4 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
kotlin("jvm") version "1.8.10"
kotlin("plugin.serialization") version "1.8.0"
kotlin("jvm") version "1.9.10"
kotlin("plugin.serialization") version "1.9.0"
`maven-publish`
signing
id("org.jlleitschuh.gradle.ktlint") version "11.3.1"
Expand All @@ -29,7 +29,6 @@ val kaml: String by project

dependencies {
implementation("com.amplitude:evaluation-core:$experimentEvaluationVersion")
implementation("com.amplitude:evaluation-serialization:$experimentEvaluationVersion")
implementation("com.amplitude:java-sdk:$amplitudeAnalytics")
implementation("org.json:json:$amplitudeAnalyticsJson")
implementation("io.lettuce:lettuce-core:$lettuce")
Expand All @@ -53,7 +52,7 @@ publishing {
create<MavenPublication>("core") {
groupId = "com.amplitude"
artifactId = "evaluation-proxy-core"
version = "0.3.2"
version = "0.4.4"
from(components["java"])
pom {
name.set("Amplitude Evaluation Proxy")
Expand Down
34 changes: 19 additions & 15 deletions core/src/main/kotlin/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,25 @@ import com.amplitude.util.intEnv
import com.amplitude.util.json
import com.amplitude.util.longEnv
import com.amplitude.util.stringEnv
import com.charleskorn.kaml.Yaml
import com.amplitude.util.yaml
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import java.io.File

@Serializable
data class ProjectsFile(
val projects: List<Project>
val projects: List<ProjectConfiguration>
) {
companion object {
fun fromEnv(): ProjectsFile {
val project = Project.fromEnv()
val project = ProjectConfiguration.fromEnv()
return ProjectsFile(listOf(project))
}

fun fromFile(path: String): ProjectsFile {
val data = File(path).readText()
return if (path.endsWith(".yaml") || path.endsWith(".yml")) {
Yaml.default.decodeFromString(data)
yaml.decodeFromString(data)
} else if (path.endsWith(".json")) {
json.decodeFromString(data)
} else {
Expand All @@ -47,7 +47,7 @@ data class ConfigurationFile(
fun fromFile(path: String): ConfigurationFile {
val data = File(path).readText()
return if (path.endsWith(".yaml") || path.endsWith(".yml")) {
Yaml.default.decodeFromString(data)
yaml.decodeFromString(data)
} else if (path.endsWith(".json")) {
json.decodeFromString(data)
} else {
Expand All @@ -58,19 +58,17 @@ data class ConfigurationFile(
}

@Serializable
data class Project(
val id: String,
data class ProjectConfiguration(
val apiKey: String,
val secretKey: String,
val deploymentKeys: Set<String>
val managementKey: String
) {
companion object {
fun fromEnv(): Project {
val id = checkNotNull(stringEnv(EnvKey.PROJECT_ID)) { "${EnvKey.PROJECT_ID} environment variable must be set." }
fun fromEnv(): ProjectConfiguration {
val apiKey = checkNotNull(stringEnv(EnvKey.API_KEY)) { "${EnvKey.API_KEY} environment variable must be set." }
val secretKey = checkNotNull(stringEnv(EnvKey.SECRET_KEY)) { "${EnvKey.SECRET_KEY} environment variable must be set." }
val deploymentKey = checkNotNull(stringEnv(EnvKey.EXPERIMENT_DEPLOYMENT_KEY)) { "${EnvKey.SECRET_KEY} environment variable must be set." }
return Project(id, apiKey, secretKey, setOf(deploymentKey))
val managementKey = checkNotNull(stringEnv(EnvKey.EXPERIMENT_MANAGEMENT_KEY)) { "${EnvKey.EXPERIMENT_MANAGEMENT_KEY} environment variable must be set." }
return ProjectConfiguration(apiKey, secretKey, managementKey)
}
}
}
Expand All @@ -80,6 +78,7 @@ data class Configuration(
val port: Int = Default.PORT,
val serverUrl: String = Default.SERVER_URL,
val cohortServerUrl: String = Default.COHORT_SERVER_URL,
val deploymentSyncIntervalMillis: Long = Default.DEPLOYMENT_SYNC_INTERVAL_MILLIS,
val flagSyncIntervalMillis: Long = Default.FLAG_SYNC_INTERVAL_MILLIS,
val cohortSyncIntervalMillis: Long = Default.COHORT_SYNC_INTERVAL_MILLIS,
val maxCohortSize: Int = Default.MAX_COHORT_SIZE,
Expand All @@ -91,6 +90,10 @@ data class Configuration(
port = intEnv(EnvKey.PORT, Default.PORT)!!,
serverUrl = stringEnv(EnvKey.SERVER_URL, Default.SERVER_URL)!!,
cohortServerUrl = stringEnv(EnvKey.COHORT_SERVER_URL, Default.COHORT_SERVER_URL)!!,
deploymentSyncIntervalMillis = longEnv(
EnvKey.DEPLOYMENT_SYNC_INTERVAL_MILLIS,
Default.DEPLOYMENT_SYNC_INTERVAL_MILLIS
)!!,
flagSyncIntervalMillis = longEnv(
EnvKey.FLAG_SYNC_INTERVAL_MILLIS,
Default.FLAG_SYNC_INTERVAL_MILLIS
Expand Down Expand Up @@ -164,11 +167,11 @@ object EnvKey {
const val SERVER_URL = "AMPLITUDE_SERVER_URL"
const val COHORT_SERVER_URL = "AMPLITUDE_COHORT_SERVER_URL"

const val PROJECT_ID = "AMPLITUDE_PROJECT_ID"
const val API_KEY = "AMPLITUDE_API_KEY"
const val SECRET_KEY = "AMPLITUDE_SECRET_KEY"
const val EXPERIMENT_DEPLOYMENT_KEY = "AMPLITUDE_EXPERIMENT_DEPLOYMENT_KEY"
const val EXPERIMENT_MANAGEMENT_KEY = "AMPLITUDE_EXPERIMENT_MANAGEMENT_API_KEY"

const val DEPLOYMENT_SYNC_INTERVAL_MILLIS = "AMPLITUDE_DEPLOYMENT_SYNC_INTERVAL_MILLIS"
const val FLAG_SYNC_INTERVAL_MILLIS = "AMPLITUDE_FLAG_SYNC_INTERVAL_MILLIS"
const val COHORT_SYNC_INTERVAL_MILLIS = "AMPLITUDE_COHORT_SYNC_INTERVAL_MILLIS"
const val MAX_COHORT_SIZE = "AMPLITUDE_MAX_COHORT_SIZE"
Expand All @@ -185,8 +188,9 @@ object EnvKey {

object Default {
const val PORT = 3546
const val SERVER_URL = "https://api.lab.amplitude.com"
const val SERVER_URL = "https://flag.lab.amplitude.com"
const val COHORT_SERVER_URL = "https://cohort.lab.amplitude.com"
const val DEPLOYMENT_SYNC_INTERVAL_MILLIS = 60 * 1000L
const val FLAG_SYNC_INTERVAL_MILLIS = 10 * 1000L
const val COHORT_SYNC_INTERVAL_MILLIS = 60 * 1000L
const val MAX_COHORT_SIZE = Int.MAX_VALUE
Expand Down
Loading
Loading