Hi all, me and my team are trying to setup sticky ...
# ask-questions
n
Hi all, me and my team are trying to setup sticky bucketing using the Java/Kotlin SDK but are having a hard time doing it. Can anyone assist? This is our current implementation (we are testing it locally trying to observe what happens to the same user id when using stickybucketing vs. when not).
Copy code
val trackingCallback = object : TrackingCallback {
    override fun <ValueType : Any?> onTrack(
        experiment: Experiment<ValueType?>,
        experimentResult: ExperimentResult<ValueType?>,
    ) {
        println("[TrackingCallback] Experiment is: $experiment")
        println("[TrackingCallback] ExperimentResult is: ${experimentResult.toJson()}")
    }
}

val stickyBucketService = object : StickyBucketService {
    override fun getAssignments(
        attributeName: String?,
        attributeValue: String?,
    ): StickyAssignmentsDocument? {
        println("[StickyBucketService] Getting assignments")
        return StickyAssignmentsDocument(
            "id",
            "b0c7f2f4-7575-4c31-88b2-823d2c88484f",
            mapOf("test__0" to "0"),
        )
    }

    override fun saveAssignments(doc: StickyAssignmentsDocument?) {
        println("[StickyBucketService] Saving assignments $doc")
    }

    override fun getAllAssignments(attributes: Map<String?, String?>?): Map<String?, StickyAssignmentsDocument?>? {
        println("[StickyBucketService] Getting all assignments")
        return null
    }
}

fun main() {
    val featuresRepository = GBFeaturesRepository
        .builder()
        .apiHost("MY_HOST")
        .clientKey("MY_CLIENT_KEY")
        .refreshStrategy(FeatureRefreshStrategy.STALE_WHILE_REVALIDATE)
        .build()
        .apply {
            initialize()
        }
    val ctx = GBContext
        .builder()
        .featuresJson(featuresRepository.featuresJson)
        .attributesJson(
            """
                {
                    "id": "b0c7f2f4-7575-4c31-88b2-823d2c88484f"
                }
            """.trimIndent(),
        )
        .trackingCallback(trackingCallback)
        .enabled(true)
        .isQaMode(false)
        .stickyBucketService(stickyBucketService)
        .build()
    val gb = GrowthBook(ctx)
    val result = gb.getFeatureValue("test", "error")
    println("Result is: $result")
}
looking 1
s
@freezing-postman-69602 Can you offer any help here?
f
Heyy.. the code you shared, especially the custom
stickyBucketService
needs some help.
getAllAssignments
returns null and
saveAssignments
doesn't do anything and
getAssignments
returns sort of a hard coded value regardless of the
attr
value or name.
when
getAllAssignments
returns null, Growthbook thinks that there are no assigned docs, evaluates the experiment normally, assigns a variation and tries to save it for future use using
saveAssignments
. if you don't require custom implementation for sticky bucketing, you could use
InMemoryStickyBucketServiceImpl
that relies on the local storage for sticky bucketing. Here's an example:
Copy code
// 1. Create the in-memory storage
val localStorage = HashMap<String, StickyAssignmentsDocument>()

// 2. Initialize the sticky bucket service
val stickyBucketService = InMemoryStickyBucketServiceImpl(localStorage)

// 3. Set up features repository

// 4. Create GBContext with sticky bucketing
    val context = GBContext
        .builder()
        .featuresJson(featuresRepository.featuresJson)
        .attributesJson("""{"id": "b0c7f2f4-7575-4c31-88b2-823d2c88484f"}""")
        .stickyBucketService(stickyBucketService)
        .stickyBucketIdentifierAttributes(listOf("id")) // Key part!
        .enabled(true)
        .isQaMode(false)
        .build()
Once you do that, with sticky bucketing, you should see the same variation for the user even when your targeting conditions or experiment parameters change.
let us know if you need more details on how this works.
a
Hello @freezing-postman-69602, thank you for your help. We are still debugging the sdk in order to get to know to make things work, and the point is both get methods are not being called. Whatever we return in both methods. The fact is they are not being called
f
I hope you've fixed the stickyBucketService and set the
stickyBucketIdentifierAttributes
. Do you mind sharing more about: 1. What does your feature "test" look like in the GrowthBook dashboard? What are the rules? 2. What's the targeting condition? I'm happy to collab w/ you to dig more into this.
a
I am going to undo my POC to Java and test it again. I swapped to the Kotlin SDK - btw I left a message in the channel about it - and it does not have the
stickyBucketIdentifierAttributes
api. @nutritious-garden-91325 can you please share what Madhu is asking, please?
n
Hi @freezing-postman-69602. Thanks for the help. This is the current flag rules in growthbook. Is not targeting a specific audience. Is a single a/b test that is supposed to show to 100% of users. Don't know if it matters, but this experiment was first set up with a 50/50 split and then I changed the configuration to 99/1 split. We are trying to force a scenario where the user would flip to another variant so we can test exactly how stickybucketing works.
Copy code
"features":{"test":{"defaultValue":"NOT IN EXPERIMENT","rules":[{"id":"fr_4gtibomdqbr94v","coverage":1,"hashAttribute":"id","bucketVersion":1,"seed":"3a7577e0-eb80-4a14-863f-f29db9fea0c7","hashVersion":2,"variations":["OFF","ON"],"weights":[0.99,0.01],"key":"test","meta":[{"key":"0","name":"Control"},{"key":"1","name":"Variation 1"}],"phase":"2","name":"test-2"}]}