GithubHelp home page GithubHelp logo

flagsmith / flagsmith-java-client Goto Github PK

View Code? Open in Web Editor NEW
20.0 14.0 19.0 432 KB

Java Client for Flagsmith. Ship features with confidence using feature flags and remote config. Host yourself or use our hosted version at https://www.flagsmith.com/

Home Page: https://www.flagsmith.com/

License: BSD 3-Clause "New" or "Revised" License

Java 100.00%
feature-flags feature-toggles feature-flag ci cd continuous-integration java sdk remote-config feature-flagging

flagsmith-java-client's Introduction

Feature Flag, Remote Config and A/B Testing platform, Flagsmith

Stars Docker Pulls Docker Image Size Join the Discord chat Coverage Built with Depot

Flagsmith is an open source, fully featured, Feature Flag and Remote Config service. Use our hosted API, deploy to your own private cloud, or run on-premise.

Flagsmith

Flagsmith makes it easy to create and manage features flags across web, mobile, and server side applications. Just wrap a section of code with a flag, and then use Flagsmith to toggle that feature on or off for different environments, users or user segments.

Get up and running in less than a minute:

curl -o docker-compose.yml https://raw.githubusercontent.com/Flagsmith/flagsmith/main/docker-compose.yml
docker-compose -f docker-compose.yml up

The application will bootstrap an admin user, organisation, and project for you. You'll find a link to set your password in your Compose logs:

Superuser "[email protected]" created successfully.
Please go to the following page and choose a password: https://localhost:8000/password-reset/confirm/.../...

Flagsmith Screenshot

Features

  • Feature flags. Release features with confidence through phased roll-outs.
  • Remote config. Easily toggle individual features on and off, and make changes without deploying new code.
  • A/B and Multivariate Testing. Use segments to run A/B and multivariate tests on new features. With segments, you can also introduce beta programs to get early user feedback.
  • Organization Management. Organizations, projects, and roles for team members help keep your deployment organized.
  • Integrations. Easily enhance Flagsmith with your favourite tools.

Trying Flagsmith

Flagsmith hosted SaaS

You can try our hosted version for free at https://flagsmith.com/

Flagsmith Open Source

The Flagsmith API is built using Python 3, Django 2, and DjangoRestFramework 3. You can try the application out using:

We also have options for deploying to AWS, GCP, Azure and On-Premise. If you need help getting up and running, please get in touch!

Overview

This repository is formed of 2 core components, the REST API (found in /api) and the web-based administrator dashboard (found in /frontend) that you can use to manage Flagsmith. Technical documentation for each component can be found at the API and Frontend pages within our Documentation

These two components run as separate applications. The web-based dashboard is a single page app that communicates via REST calls to the API.

Resources

Acknowledgements

Thank you to Uffizzi for providing ephemeral environments to preview pull requests.

flagsmith-java-client's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flagsmith-java-client's Issues

Unable to use segment with traits

I have started a poc for our client. Using 5.1.2. My current focus on segments. Have created a feature flag "my_api_mock_enabled" and switched ON. Have created a feature specific segment named as "mock_incl_rule" with a trait key "firstName" and trait value "i_m_mock". Switched it ON. Now, in my Java code I am using identifier to evaluate the feature flag as below -

// Get current user details
User user = sessionService.getCurrentUser( httpRequest );
String userIdentifier = uniqueHash( user );

// Get flags based on above user details
Flags flags = flagsmithClient.getIdentityFlags( userIdentifier, Collections.singletonMap( "firstName", user.getFirstName() )) ;

Boolean mockEnabled = flags.isFeatureEnabled( "my_api_mock_enabled" );

Why this Boolean flag is coming always TRUE ??? My expectation is it should come FALSE if my user has first name other than "i_m_mock".

Help is appreciated - @dabeeeenster

StackOverflow error when intializing FlagsmithConfig with analytics as a SpringBootBean

	at com.flagsmith.config.FlagsmithConfig.hashCode(FlagsmithConfig.java:24) ~[flagsmith-java-client-6.1.0.jar:na]
	at com.flagsmith.FlagsmithApiWrapper.hashCode(FlagsmithApiWrapper.java:28) ~[flagsmith-java-client-6.1.0.jar:na]
	at com.flagsmith.threads.AnalyticsProcessor.hashCode(AnalyticsProcessor.java:19) ~[flagsmith-java-client-6.1.0.jar:na]
	at com.flagsmith.config.FlagsmithConfig.hashCode(FlagsmithConfig.java:24) ~[flagsmith-java-client-6.1.0.jar:na]
	at com.flagsmith.FlagsmithApiWrapper.hashCode(FlagsmithApiWrapper.java:28) ~[flagsmith-java-client-6.1.0.jar:na]
	at com.flagsmith.threads.AnalyticsProcessor.hashCode(AnalyticsProcessor.java:19) ~[flagsmith-java-client-6.1.0.jar:na]
	at com.flagsmith.config.FlagsmithConfig.hashCode(FlagsmithConfig.java:24) ~[flagsmith-java-client-6.1.0.jar:na]
	at com.flagsmith.FlagsmithApiWrapper.hashCode(FlagsmithApiWrapper.java:28) ~[flagsmith-java-client-6.1.0.jar:na]
	at com.flagsmith.threads.AnalyticsProcessor.hashCode(AnalyticsProcessor.java:19) ~[flagsmith-java-client-6.1.0.jar:na]

I am providing the sample code that crashes from a simple SpringBoot application which declares the FlagsmithClient as a Bean, like SpringBoot dictates.

package com.cyberark.epm.account.config;

import com.flagsmith.FlagsmithClient;
import com.flagsmith.config.FlagsmithCacheConfig;
import com.flagsmith.config.FlagsmithConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.ResponseEntity;

import java.util.List;

@Configuration
public class FlagsmithConfiguration {

    @Bean
    public FlagsmithClient flagsmithClient(
            @Value("${flagsmith.apiUrl}") String apiUrl,
            @Value("${flagsmith.key}") String key
    ) {

        FlagsmithConfig flagsmithConfig = FlagsmithConfig.newBuilder()
                // withEnableAnalytics(true) Causes a stackoverflow
                .withEnableAnalytics(true)
                .baseUri(apiUrl).build();

        return FlagsmithClient
                .newBuilder()
                .setApiKey(key)
                .withConfiguration(flagsmithConfig)
                .withCache(FlagsmithCacheConfig
                        .newBuilder()
                        .build())
                .build();
    }

}

The code crashes when trying to inject FlagsmithClient to another bean in the project.

It looks like SpringBoot calls for the hashcode function which is cyclic.

Maybe adding Lombok's @HashCodeExclude annotation on one of the (cyclic) dependencies can resolve the issue.
For instance, inside AnalyticsProcessor's 'api' member, which was dealt with similar issues in the past:
@ToString.Exclude private FlagsmithSdk api;

Push to mvn with Github Actions

We should sign and push our jar to public mvn repos based on github releases and actions, so github and mvn repo are in sync.

  • Creating a release in Github pushes that version to Maven
  • New version can be added to a java application's dependencies and used to communicate with Flagsmith

Tests not running successfully

Hi there,

I just forked the project and ran the unit tests.

These tests are successful:
BulletTrainClientTest.testClient_When_Get_Features_For_User_Then_Success
BulletTrainClientTest.testClient_When_Get_Features_Then_Success
BulletTrainClientTest#testClient_When_Get_User_Traits_For_Invalid_User_Then_Return_Empty

These ones are not:
BulletTrainClientTest.testClient_When_Get_User_Trait_Then_Success
BulletTrainClientTest.testClient_When_Get_User_Trait_Update_Then_Updated
BulletTrainClientTest.testClient_When_Get_User_Traits_For_Keys_Then_Success
BulletTrainClientTest.testClient_When_Get_User_Traits_Then_Success

Thank you,
Olga

NullPointerException on com.flagsmith.models.Flags.getFeatureValue(String)" because "value" is null

Library version: 6.1.0
JVM: 21

Client setup:

  private val cache = FlagsmithCacheConfig
    .newBuilder()
    .expireAfterWrite(1, TimeUnit.MINUTES)
    .enableEnvLevelCaching("local_cache")
    .maxSize(1000)
    .build()
  private val client = FlagsmithFeatureClient
    .newBuilder()
    .setApiKey(environmentKey)
    .withCache(cache)
    .build()

Error:

java.lang.NullPointerException: Cannot invoke "com.flagsmith.models.Flags.getFeatureValue(String)" because "value" is null

Investigation:

in the underlying code of com.flagsmith.models.Flags we found that method we use:

  /**
   * Get the feature value, null if not present.
   *
   * @param featureName Feature name
   * @return
   */
  public Object getFeatureValue(String featureName) throws FlagsmithClientError {
    return getFlag(featureName).getValue();
  }

invokes other public method:

  /**
  * Get the feature, null if not present.
  *
  * @param featureName feature name
  * @return
  */
 public BaseFlag getFlag(String featureName) throws FlagsmithClientError {
   if (!flags.containsKey(featureName)) {
     if (defaultFlagHandler != null) {
       return defaultFlagHandler.evaluateDefaultFlag(featureName);
     }
     throw new FeatureNotFoundError("Feature does not exist: " + featureName);
   }

   BaseFlag flag = flags.get(featureName);

   if (analyticsProcessor != null && flag instanceof Flag) {
     Flag flagObj = (Flag) flag;
     if (flagObj.getFeatureId() != null) {
       analyticsProcessor.trackFeature(flagObj.getFeatureName());
     }
   }

   return flag;
 }

where it's indicated that it can return null, however getFeatureValue method doesn't check if returned value is null

Could you please address this issue?

`getIdentityFlags("identity").getFeatureValue("feature")` returns `com.fasterxml.jackson.databind.node.XXX` rather than `java.lang.XXX`

An example program which exhibits the issue:

package com.flagsmith;
import com.flagsmith.models.Flags;

public class App
{
    public static void main( String[] args ) throws Exception
    {
        FlagsmithClient flagsmith = FlagsmithClient.newBuilder()
            .setApiKey("<server-key>")
            .build();

        Flags flags = flagsmith.getIdentityFlags("identity");
        Object stringFeatureValue = flags.getFeatureValue("feature");

        System.out.println(stringFeatureValue.getClass());
    }
}

This prints e.g. class com.fasterxml.jackson.databind.node.TextNode if "feature" has a string value, whereas we would expect it to print class java.lang.String

Default flags when fetching all flags

Hi @dabeeeenster ,

We have just noticed that when we use getFeatureFlags(*) and identifyUserWithTraits(user, traits), we get the raw values directly from Flagsmith, so no default values are used (which are very important to us). This is specially problematic in the scenario where we use a proxy to secure the Flagsmith endpoints (Flagsmith -> BFF (just forwards flags as received) -> frontend).

Since this is something that everyone should do (have sane defaults), we would like to extend the SDK with the following logic:

  • Analog to setDefaultFlagPredicate and setDefaultFlagValueFunction, we would like to have a setDefaultFlags method.
  • setDefaultFlags would accept an array of strings (feature flag names).
  • If there is an error when fetching flags from the API, we then create default flags (if the string array was set) with the default values set above.
  • If there is no error, but the flag was not received from Flagsmith, we can insert it with default values. I thought you may have a stronger opinion on this point, so we can always add further configuration for this behaviour if required.

This is the behaviour we would like but you guys know best how your API is consumed. Any thoughts?

Cheers,
Olga

Can't fetch environment document, 404 and 403

I am using Server-Side Environment Keys. The updateEnvironment() operation in Java SDK is throwing an error thus I can’t request flags. I have started calling this operation while debugging the issue with getIdentityFlags().

Flagsmith: error when getting flags. Request: https://edge.api.flagsmith.com/api/v1/environment-document/, Response: Response{protocol=h2, code=404, message=, url=https://edge.api.flagsmith.com/api/v1/environment-document/} body[]

A similar issue happens when I try to fetch identity flags, this time it is 403.

2023-12-15 10:22:39.967 [pool-7-thread-2] ERROR com.flagsmith.FlagsmithClient traceId:  spanId:
                 - Flagsmith: error when getting flags. Request: https://edge.api.flagsmith.com/api/v1/environment-document/, Response: Response{protocol=h2, code=403, message=, url=https://edge.api.flagsmith.com/api/v1/environment-document/} body[]
2023-12-15 10:22:40.172 [Thread-2] ERROR com.flagsmith.FlagsmithClient traceId:  spanId:
                 - Flagsmith: Execution failed on Environment loading.
java.util.concurrent.ExecutionException: com.flagsmith.exceptions.FlagsmithApiError
        at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:395)
        at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2022)
        at com.flagsmith.FlagsmithApiWrapper.getEnvironment(FlagsmithApiWrapper.java:255)
        at com.flagsmith.FlagsmithClient.updateEnvironment(FlagsmithClient.java:55)
        at com.flagsmith.threads.PollingManager$1.run(PollingManager.java:41)
Caused by: com.flagsmith.exceptions.FlagsmithApiError: null
        at com.flagsmith.threads.RequestProcessor.lambda$executeAsync$0(RequestProcessor.java:112)
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.base/java.lang.Thread.run(Thread.java:829)
2023-12-15 10:22:40.173 [Thread-2] ERROR com.flagsmith.FlagsmithClient traceId:  spanId:
                 - Flagsmith: Unable to update environment from API. No environment configured - using defaultHandler if configured.

with the initialization code

FlagsmithConfig flagsmithConfig = FlagsmithConfig.newBuilder()
                                                 .withLocalEvaluation(true)
                                                 .withEnableAnalytics(true)
                                                 .withEnvironmentRefreshIntervalSeconds(15)
                                                 // .baseUri()
                                                 .build();

return FlagsmithClient.newBuilder()
                      .setApiKey(featureFlagConfig.getString("apiKey"))
                      .withConfiguration(flagsmithConfig)
                      .enableLogging(logger)
                      .enableLogging(FlagsmithLoggerLevel.ERROR)
                      .build();

Version: 7.1.1
JVM: OpenJDK Runtime Environment Corretto-11.0.17.8.1 (build 11.0.17+8-LTS)

RequestProcessor does not propejrly handle retries.

The RequestProcessor is re-using the same OkHttp Call object in its retry loop (see

).

However, the underlying RealCall object is statefull and can only be used once, otherwise an IllegalStateException is thrown (see https://github.com/square/okhttp/blob/2756ea1c40cd1e7c54ea63fa4a761d4a6bc74d8f/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt#L154 ).
As a result, the catch IOException (

) is not enough, and we immediately fall to the global catch ( ) .

A simple fix would be to recreate a new Call object within the loop instead of outside of it.

`identifyUserWithTraits` sends JSON blobs to Flagsmith

I'm trying to set traits on a user using identifyUserWIthTraits, but the traits in Flagsmith aren't what I expect.

Current behavior:
A trait with the value "[email protected]" gets set in Flagsmith as "{'type': 'unicode', 'value': '[email protected]'}"

Expected behavior:
The value in Flagsmith is "[email protected]"

We're currently using bullet-train-client version 1.6.

Additionally, an example of setting traits in the Readme would be amazing!

Caching not working

Hi,

I'm using the flagsmith-java-client version 2.8, and I'm initializing the client as it's shown in the tutorial.

Overriding the defaults:
.withCache(FlagsmithCacheConfig .newBuilder() .maxSize(100) .expireAfterWrite(10, TimeUnit.MINUTES) .recordStats() .build()) .build();

and using the defaults:
.withCache(FlagsmithCacheConfig .newBuilder() .build()) .build()

None of them works. I use the method "getFeatureFlagValue(featureKey)" to retrieve the flag value, but none of the responses is cached.

Also, when checking the cache stats, everything appears setted to zero.

Can you help?

Thanks in advance.

Bug: Immutable type created, causes exception to be thrown

Hi @dabeeeenster ,

We are using this library with kotlin and we are getting exceptions when the feature flag list needs to be extended because the flag is missing in the server. The reason is that the feature flag list is created as immutable.

Here is where the code needs to be fixed:

file: FlagsmithApiWrapper.java

// from:
List<Flag> featureFlags = Arrays.asList(mapper.readValue(response.body().string(),
            Flag[].class));

// to:
List<Flag> featureFlags = new ArrayList<>(Arrays.asList(
            mapper.readValue(response.body().string(),
            Flag[].class)));

Maybe you should double check everywhere where Arrays.asList is used (as this creates an immutable list). If the list needs to be modifiable then wrapping it with new ArrayList<>() should fix it (this creates a mutable list).

Cheers,
Olga

Add support for analytics

As a developer, I would like the Java SDK to support sending flag analytics to the Flagsmith API, so that we can view flag evaluation in the WebApp.

How to resolve {"detail":"Authentication credentials were not provided."} while calling any GET or POST request via rest API while configuring flagsmith java client

Hi @anyone,
I am trying to use curl command curl -X GET "http://localhost:8000/api/v1/projects/p1/features/" -H "Content-type: application/json" -H "X-Auth-Token: ***" , i observe the above error.

I tried changing -H "Authorization: ****" , tried apssing environment key along with this .
How to pass API Key for my GET and POST requests to work ?

Caching

Hi Ben,

I would like to add this library for in memory caching to the Java SDK. It doesn't add any further dependencies. It is lightweight and very performant.

https://github.com/ben-manes/caffeine

Here is a performance analysis of different caching libraries:
https://programmer.group/caffeine-the-king-of-local-cache-performance.html

The goal is that if we call hasFeatureFlag(user, "flag-name") 3 times, it doesn't result in 3 HTTP calls within 1 second.

Could you confirm if you are ok with this please before I start coding?

Cheers,
Olga

Provided default flags should be used when unable to establish connectivity to Flagsmith API

Supporting Information
Java Flagsmith SDK Version: 5.1.1

Summary
If the Flagsmith API is not accessible when launching an application using local evaluation, an error is thrown instead of falling back to the provided default flags.

Code Snippet

@Service
public class FlagsmithService {
  private static final Logger LOG = LoggerFactory.getLogger(FlagsmithService.class);
  private final FlagsmithClient flagsmithClient;
  private static final Map<String, DefaultFlag> defaultFlagsMap = new HashMap<>();
  private static ResourceLoader resourceLoader = new DefaultResourceLoader();
  private final ProfileService profileService;

  @Autowired
  public FlagsmithService(
      @Value("${flagsmith.api_url}") String api_url,
      @Value("${flagsmith.api_key}") String api_key,
      @Value("${flagsmith.enable_analytics:false}") Boolean enableAnalytics,
      @Value("${flagsmith.poll_rate:30}") int poll_rate,
      @Value("${flagsmith.default_flags:~/default-flags.json}") String defaultFlagsDir,
      ProfileService profileService) {
    this.profileService = profileService;
    this.flagsmithClient = FlagsmithClient.newBuilder()
        .setApiKey(api_key)
        .setDefaultFlagValueFunction(FlagsmithService::defaultFlagHandler)
        .withConfiguration(FlagsmithConfig.newBuilder()
            .baseUri(api_url)
            .withEnableAnalytics(enableAnalytics)
            .withLocalEvaluation(true)
            .withEnvironmentRefreshIntervalSeconds(poll_rate)
            .build())
        .build();
    setDefaultFlags(defaultFlagsDir);
  }
// <-- SNIPPED UNRELATED CODE -->
}

Steps to Reproduce

  1. Ensure the Flagsmith API you are pointing to is offline or otherwise inaccessible
  2. Launch your application
  3. Note that the request to fetch state in support of local evaluation has failed, as expected:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [zz.cortex.base.services.flagsmith.FlagsmithService]: Constructor threw exception
	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:223) ~[spring-beans-6.0.3.jar:6.0.3]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:110) ~[spring-beans-6.0.3.jar:6.0.3]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:321) ~[spring-beans-6.0.3.jar:6.0.3]
	... 33 common frames omitted
Caused by: java.lang.RuntimeException: java.util.concurrent.ExecutionException: com.flagsmith.exceptions.FlagsmithApiError
	at com.flagsmith.FlagsmithApiWrapper.getEnvironment(FlagsmithApiWrapper.java:255) ~[flagsmith-java-client-5.1.1.jar:na]
	at com.flagsmith.FlagsmithClient.updateEnvironment(FlagsmithClient.java:60) ~[flagsmith-java-client-5.1.1.jar:na]
	at com.flagsmith.threads.PollingManager.<init>(PollingManager.java:27) ~[flagsmith-java-client-5.1.1.jar:na]
	at com.flagsmith.FlagsmithClient$Builder.build(FlagsmithClient.java:470) ~[flagsmith-java-client-5.1.1.jar:na]
	at zz.cortex.base.services.flagsmith.FlagsmithService.<init>(FlagsmithService.java:51) ~[main/:na]
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:na]
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[na:na]
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480) ~[na:na]
	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:210) ~[spring-beans-6.0.3.jar:6.0.3]
	... 35 common frames omitted
Caused by: java.util.concurrent.ExecutionException: com.flagsmith.exceptions.FlagsmithApiError
	at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:396) ~[na:na]
	at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2096) ~[na:na]
	at com.flagsmith.FlagsmithApiWrapper.getEnvironment(FlagsmithApiWrapper.java:248) ~[flagsmith-java-client-5.1.1.jar:na]
	... 45 common frames omitted
Caused by: com.flagsmith.exceptions.FlagsmithApiError: null
	at com.flagsmith.threads.RequestProcessor.lambda$executeAsync$0(RequestProcessor.java:112) ~[flagsmith-java-client-5.1.1.jar:na]
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[na:na]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
	at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
  1. Expected Behavior: Connectivity failed, proceed with the provided default flag values and try to connect again on next poll.
  2. Actual Behavior: Application exception occurs - application halts.

gz#344

Remove flag type as an entity concept

Hi @dabeeeenster ,

In earlier versions of Flagsmith, you could either have a FLAG or a CONFIG type. Now we get STANDARD as well sometimes.
This was kind of relevant before because you would either use the toggle or the value but you couldn't use both.

With new versions of Flagsmith (at least the version we have), you always have toggle and value.

My question is, is the type relevant at all? We have not been using the type field at all in our code since we know how to consume each of our toggles, plus is not like you can manually set in the UI if a flag is of a specific type.

Cheers,
Olga

Cache policy with environment flag and identity flags conflicts

Let say I configure a FlagsmithCache of 1 minute.

If I call getEnvironmentFlags and then call getIdentityFlags, then the first cached call will be returned for the second call.

I feel like this behavior is error prone as we don't expect to have the "default" value of environment flags when we request for a specific identity override, even if we cache the results of the API.

EnableAnalytics - Error parsing analytics data to JSON

Hi,

Part from our implementation:

@Slf4j
public class FlagsmithFeatureFlagClient implements FeatureFlagClient {
    private static final Duration DEFAULT_CACHE_EXPIRATION = Duration.ofMinutes(5);
    private static final int DEFAULT_CACHE_SIZE = 100;
    private final FlagsmithClient flagsmithClient;
    public FlagsmithFeatureFlagClient(FeatureFlagClientConfig config) {
        Duration cacheExpiration = ofNullable(config.getCacheExpiration()).orElse(DEFAULT_CACHE_EXPIRATION);
        int cacheSize = ofNullable(config.getCacheSize()).orElse(DEFAULT_CACHE_SIZE);
        this.flagsmithClient = FlagsmithClient.newBuilder()
                .setApiKey(config.getEnvironmentKey())
                .withConfiguration(FlagsmithConfig.newBuilder()
                        .withEnableAnalytics(true)
                        .baseUri(config.getApiUrl())
                        .build())
                .withCache(FlagsmithCacheConfig
                        .newBuilder()
                        .enableEnvLevelCaching(config.getEnvironmentKey())
                        .expireAfterWrite((int) cacheExpiration.getSeconds(), TimeUnit.SECONDS)
                        .maxSize(cacheSize)
                        .build())
                .enableLogging(log)
                .build();
    }
    @Override
    @SneakyThrows(FlagsmithClientError.class)
    public Flag getFlag(Feature feature, String identity) {
        BaseFlag baseFlag = flagsmithClient.getIdentityFlags(identity).getFlag(name(feature));
        return convert(feature, baseFlag);
    }
    private Flag convert(Feature feature, BaseFlag baseFlag) {
        return Flag.builder()
                .feature(feature)
                .value(baseFlag.getValue())
                .enabled(ofNullable(baseFlag.getEnabled()).orElse(false))
                .build();
    }

    private String name(Feature feature) {
        return feature.name().toLowerCase();
    }
}

The error: Error parsing analytics data to JSON

Stacktrace:

com.fasterxml.jackson.databind.JsonMappingException: (was java.util.ConcurrentModificationException) (through reference chain: java.util.HashMap["kenshoo_local_branding"])
	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:391) ~[jackson-databind-2.9.1.jar:2.9.1]
	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:351) ~[jackson-databind-2.9.1.jar:2.9.1]
	at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:316) ~[jackson-databind-2.9.1.jar:2.9.1]
	at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields(MapSerializer.java:721) ~[jackson-databind-2.9.1.jar:2.9.1]
	at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:639) ~[jackson-databind-2.9.1.jar:2.9.1]
	at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:33) ~[jackson-databind-2.9.1.jar:2.9.1]
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480) ~[jackson-databind-2.9.1.jar:2.9.1]
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319) ~[jackson-databind-2.9.1.jar:2.9.1]
	at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3893) ~[jackson-databind-2.9.1.jar:2.9.1]
	at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3207) ~[jackson-databind-2.9.1.jar:2.9.1]
	at com.flagsmith.threads.AnalyticsProcessor.flush(AnalyticsProcessor.java:123) ~[flagsmith-java-client-7.2.0.jar:?]
	at com.flagsmith.threads.AnalyticsProcessor.trackFeature(AnalyticsProcessor.java:147) ~[flagsmith-java-client-7.2.0.jar:?]
	at com.flagsmith.models.Flags.getFlag(Flags.java:188) ~[flagsmith-java-client-7.2.0.jar:?]
	at io.skai.feature.flag.client.flagsmith.FlagsmithFeatureFlagClient.getFlag(FlagsmithFeatureFlagClient.java:74) ~[feature-flags-java-client-0.1.15.jar:?]

I'd appreciate any help with this issue.

Enable to set proxy

Enable to set proxy on the OkHttpClient object in the FlagsmithConfig class. For example by creating another configuration option, withProxy(Proxy proxy) ,where the Proxy class comes from java.net.Proxy, or similiar, that sets OkHttpClient.Builder().proxy(proxy).build().

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.