Giter Club home page Giter Club logo

unleash-client-java's Issues

Local backup json file is not getting updated

Local backup json file is not getting updated when disabled labels in UI, disable /enable the lables in admin GUI , is not reflected in unleash client in multiple AWS ec2 instance, it only picks up the first time settings

Critical bug: empty of bogus backup file will crash the client at startup.

How to reproduce:

  1. Make sure /tmp/unleash-repo.json is empty or invalid json.
  2. Run the UnleashUsageTest found the the test directory.

It will crash the unleash with an constructor excpetion (se example)

Suggested solution:
Add an extra catch in ToggleBackupHandlerFile.java to make sure we also handle bogus backup-file.

java.lang.IllegalStateException: Could not extract toggles from json
    at no.finn.unleash.repository.JsonToggleParser.fromJson(JsonToggleParser.java:23)
    at no.finn.unleash.repository.ToggleBackupHandlerFile.read(ToggleBackupHandlerFile.java:29)
    at no.finn.unleash.repository.FeatureToggleRepository.<init>(FeatureToggleRepository.java:42)
    at no.finn.unleash.repository.FeatureToggleRepository.<init>(FeatureToggleRepository.java:35)
    at no.finn.unleash.DefaultUnleash.<init>(DefaultUnleash.java:22)
    at no.finn.unleash.example.UnleashUsageTest.wire(UnleashUsageTest.java:17)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)

Error-msg on first load on new node

If the tmp-backup-file is missing unleash-client fgenerates this warning:

[ WARN] 13:11:09 Unable to locate backup file:'/tmp/unleash-repo.json' []
java.io.FileNotFoundException: /tmp/unleash-repo.json (No such file or directory)
    at java.io.FileInputStream.open(Native Method) ~[?:1.8.0_05]
    at java.io.FileInputStream.<init>(FileInputStream.java:131) ~[?:1.8.0_05]
    at java.io.FileInputStream.<init>(FileInputStream.java:87) ~[?:1.8.0_05]
    at java.io.FileReader.<init>(FileReader.java:58) ~[?:1.8.0_05]
    at no.finn.unleash.repository.BackupFileHandler.read(BackupFileHandler.java:24) [unleash-client-java-1.0-SNAPSHOT.jar:?]
    at no.finn.unleash.repository.FeatureToggleRepository.<init>(FeatureToggleRepository.java:43) [unleash-client-java-1.0-SNAPSHOT.jar:?]
    at no.finn.unleash.repository.FeatureToggleRepository.<init>(FeatureToggleRepository.java:36) [unleash-client-java-1.0-SNAPSHOT.jar:?]
    at no.finn.unleash.DefaultUnleash.<init>(DefaultUnleash.java:20) [unleash-client-java-1.0-SNAPSHOT.jar:?]
    at no.finntech.talent.web.config.ApplicationConfig.unleash(ApplicationConfig.java:103) [classes/:?]
    at no.finntech.talent.web.config.ApplicationConfig$$EnhancerBySpringCGLIB$$c9f14094.CGLIB$unleash$6(<generated>) [spring-core-4.0.2.RELEASE.jar:?]
    at no.finntech.talent.web.config.ApplicationConfig$$EnhancerBySpringCGLIB$$c9f14094$$FastClassBySpringCGLIB$$5e09d657.invoke(<generated>) [spring-core-4.0.2.RELEASE.jar:?]
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) [spring-core-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312) [spring-context-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at no.finntech.talent.web.config.ApplicationConfig$$EnhancerBySpringCGLIB$$c9f14094.unleash(<generated>) [spring-core-4.0.2.RELEASE.jar:?]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_05]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_05]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_05]
    at java.lang.reflect.Method.invoke(Method.java:483) ~[?:1.8.0_05]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:580) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1094) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:989) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1014) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:957) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:855) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700) [spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760) [spring-context-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482) [spring-context-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:658) [spring-webmvc-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:530) [spring-webmvc-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:484) [spring-webmvc-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136) [spring-webmvc-4.0.2.RELEASE.jar:4.0.2.RELEASE]
    at javax.servlet.GenericServlet.init(GenericServlet.java:244) [javax.servlet-api-3.1.0.jar:3.1.0]
    at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:561) [jetty-servlet-9.1.2.v20140210.jar:9.1.2.v20140210]
    at org.eclipse.jetty.servlet.ServletHolder.initialize(ServletHolder.java:351) [jetty-servlet-9.1.2.v20140210.jar:9.1.2.v20140210]
    at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:840) [jetty-servlet-9.1.2.v20140210.jar:9.1.2.v20140210]
    at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:300) [jetty-servlet-9.1.2.v20140210.jar:9.1.2.v20140210]
    at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1347) [jetty-webapp-9.1.2.v20140210.jar:9.1.2.v20140210]
    at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:745) [jetty-server-9.1.2.v20140210.jar:9.1.2.v20140210]
    at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:492) [jetty-webapp-9.1.2.v20140210.jar:9.1.2.v20140210]
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:69) [jetty-util-9.1.2.v20140210.jar:9.1.2.v20140210]
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:117) [jetty-util-9.1.2.v20140210.jar:9.1.2.v20140210]
    at org.eclipse.jetty.server.Server.start(Server.java:355) [jetty-server-9.1.2.v20140210.jar:9.1.2.v20140210]
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:99) [jetty-util-9.1.2.v20140210.jar:9.1.2.v20140210]
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:60) [jetty-server-9.1.2.v20140210.jar:9.1.2.v20140210]
    at org.eclipse.jetty.server.Server.doStart(Server.java:324) [jetty-server-9.1.2.v20140210.jar:9.1.2.v20140210]
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:69) [jetty-util-9.1.2.v20140210.jar:9.1.2.v20140210]
    at no.finntech.talent.web.LocalJettyServer.start(LocalJettyServer.java:64) [test-classes/:?]
    at no.finntech.talent.web.LocalJettyServer.main(LocalJettyServer.java:28) [test-classes/:?]

Evaluate Testframework

JUnit is old and boring. Unit testing can be more fun with modern framework such as Spock.

I vote for switching to Spock.

What is your favorite test framework in java?

Improve error messages

When connecting to the unleash-server over http instead of https and the client only receives 301 it will only log 301 and not the new location header. This can make it hard for the use to understand why the client cannot connect to the server.

feat: function for returning headers

This would allow for dynamic header setting, which is important to enable rotation of auth-tokens etc without restarting.

For reference, this feature is already implemented in the Node.js SDK, see Unleash/unleash-client-node#151

My thought was that it should be possible to register a function as part of the Unleash Configuration which would return a Map (name, value) of headers to add request sent to the unleash-server. If this function is set it should take precedence over customHttpHeaders already part of the UnleashConfig.java.

Support for expecific feature change subscriber

Context
Currently I have a system that need some heavy software pieces in the case of a feature is enable. You can image that when the feature is disable I don´t need for example connection to database or Kafka or whatever. Then I am creating a reactive system that create this pieces when the feature turn on and destroy it when turn off.

In order to do that I create a subscriber like this:

@Bean
fun unleash(): Unleash {
    val config = UnleashConfig.builder()
        .appName(application)
        .instanceId(getEnv("HOSTNAME"))
        .unleashAPI(url)
        .subscriber(object : UnleashSubscriber {

            override fun togglesFetched(toggleResponse: FeatureToggleResponse) {
                if (toggleResponse.status == CHANGED) {
                    //create heavy pieces
                }
            }
        })
        .build()
    return DefaultUnleash(config)
}

My problem
My first workaround was try to check the values that interest me form 'togglesFetched' via the
'toggleResponse: FeatureToggleResponse' paramether. The problem is that this class is internal class we can not access to anything.

My seconds workaround is to check the feature value via “isEnabled” or “getVariant”. I need the ‘Unleash’ object (aka the client) inside the subcriber, but I am creating the client.
Can you see the clicle?

Temporal solution
After a talk with @ivarconr we agree follow this approach: We could create your subscriber outside and provide the Unleash instance via a setter.

class MyUnleashSubscriber implements UnleashSubscriber {
    Unleash instance;
    
    public void setInstance(Unleash unleash) {
        instance = unleash;
    }

    @Override
    public void togglesFetched(FeatureToggleResponse toggleResponse) {
        if(toggleResponse.getStatus() == CHANGED) {
            if(instance != null) {
                instance.isEnabled("Demo");
            }
        }
       }
    }

    MyUnleashSubscriber subscriber = new MyUnleashSubscriber();

        UnleashConfig unleashConfig = new UnleashConfig.Builder()
                .appName("java-test")
                .instanceId("instance y")
                .unleashAPI("https://unleash.herokuapp.com/api/")
                .subscriber(subscriber)
                        .build())
                .build();

        Unleash unleash = new DefaultUnleash(unleashConfig);
        subscriber.setInstance(unleash);

Obviously this work but I think that we can improve the support of that situation by the client allowing add subscriber dynamically after the creation or exposing the features values in the subscriber (in a external format of course)

Setup release pipeline

Our current release unleash-java-client:0.1-alpha, i did manually on my computer. We should automate the release (with a manual trigger).

Need to decide if we'll setup Travis to do the release build, or maybe FINN.no's internal build system. The release process needs credientials for sonatype repo and a password to unluck a pgp key for signing the artifact. Is it possible have these credentials secured and used by Travis?

Proxy support that recognizes -Dhttp.proxy* settings

Hello everyone,

I am currently playing around with the unleash java client. It works really well, I only struggled a little bit with the proxy configuration.

As you use HttpUrlConnection as http client, basic auth proxy settings are not recognized, i.e.:

  • http.proxyUser
  • http.proxyPassword

Therefore, it is necessary to implement a custom java.net.Authenticator. What do you think of providing such an implementation within the library itself? If so, I would try to create a PR for that.

Thank you in advance!

Publish events

The client should provide a way for users to subscribe on interesting events. Preferably without introducing third party dependencies.

Examples:

  • ready - Unleash client has fetched initial state from unleash-server is able to serve request
  • update - Unleash client got updated toggle configuration from server.
  • error - Unleash client failed fetching data from unleash-server (might want to set some retry limit?).

Change strategy interface

There have been one request to change the strategy interface and have unleash also inject which feature toggle is being checked now.

The reasoning behind it is to easier support gradual rollout in a such way that one can use the hashcode of the user in combination with the feature toggle. This will allow gradual rollout to be consistent within an toggle (eg. same users will fall within 1% and 5%) but not across different feature toggles. I see no reason to hide this information from the strategy-implementation, and most strategies can just ignore this extra parameter.

The new interface will the be:

public interface Strategy {
    String getName();

    boolean isEnabled(String toggleName, Map<String, String> parameters);
}

This will however be a breaking change, but most of our users have not yet started implementing their own strategies.

The same behavior can be achieved by having an extra config parameter in the strategy-parameters, but is more burdensome to the user.

Any thoughts?

Metric Bucket + Client Features Flag list

I noticed no.finn.unleash.metric.MetricsBucket is a non-public class, is that intentional? I was hoping to retrieve the MetricBucket via the UnleashSubscriber.clientMetrics() event to capture a Set of the feature flags the client is checking for. This could be a quick way to identify feature flags that exist (and are being called) in the client, that may not exist on the server yet. Unless there is a better alternative way for the client to know what feature flags exist within the client code base. I know from the Unleash server side, for a given application, I can get a list of Feature flags that have been triggered on the client, but are not defined on the server. I'm trying to do a similar thing, just from the client side.

4XX errors does not log anything

The client should log if it gets 400 errors from the server.

  • How noisy should it be on this?
  • Should it mute after a few errors?
  • Should this option be configurable?

Synchronous call to pull toggles when instantiating the unleash client

Right now it looks like when the unleash client is instantiated a background thread is setup to query the toggles from the server. I am running into an issue where a call to getFeatureToggleNames() is returning an empty list because the call is made too soon after the instantiation of the client and no backup file existed.

Can the instantiation make an synchronous call to update first and then setup the background thread?

ClientRegistration Event - Suggestions

Small change suggestion.
You may want to change getInterval() to getSendMetricInterval() as this could easily be confused with the fetchTogglesInterval value from the UnleashConfig if the source code isn't examined.

Also, I noticed that the ClientRegistration is pulling a several values from the UnleashConfig. Would it make more sense to instead just store the entire UnleashConfig as an event variable instead of the few selected fields? That way, someone implementing the clientRegistered() method of the UnleashSubscriber can pick/choose which fields are relevant for them to log.

Plugin Api to registrer custom strategies

It would have been nice with the a possibility to add strategies at runtime. E.g. adding the following addStrategy method:

interface Unlesh{
boolean isEnabled(String toggleName);
boolean isEnabled(String toggleName, boolean defaultSetting);
addStrategy(Strategy strategy);
}

Problem with userWithId strategy

I'm putting this here even thought it relates to the Finn client.
There was additional whitespace after an id in the parameter so it didn't match.
We should maybe remove whitespace from the parameters?
This might effect more than just the userWithId strategy.

skjermbilde 2015-03-05 kl 17 07 03

java client -fail gracefully

copied from Unleash/unleash#15

The client should not stop the application from starting or working if unleash-server is unavailable or acting up.

Enforce defaults for every feature toggle used by the application.

Strategy for strategies

Unleash has gotten some pull requests to the Finn client and it is good that people want to use the service. I just want to raise a concern.

Right now this version has the following strategies:

  • DefaultStrategy
  • UnknownStrategy

Finn client has the following strategies:

  • ActiveForUserWithIdStrategy
  • BetaUserStrategy
  • ByHostNameStrategy
  • GradualRolloutRandomStrategy
  • RemoteAddrStrategy

Should we not move more of the strategies from the Finn client over to the open source one?

I also suggest that we add a markdown file that describes the strategies with example use cases.

getting error while using unleash client while running web app cygwin

2019-02-07 12:59:51.570  WARN 5092 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Could not refresh feature toggles
no.finn.unleash.UnleashException: Could not fetch toggles
        at no.finn.unleash.repository.HttpToggleFetcher.fetchToggles(HttpToggleFetcher.java:48)
        at no.finn.unleash.repository.FeatureToggleRepository.lambda$updateToggles$0(FeatureToggleRepository.java:43)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.net.ConnectException: Connection refused: connect
        at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
        at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
        at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
        at java.net.Socket.connect(Socket.java:589)
        at sun.net.NetworkClient.doConnect(NetworkClient.java:175)
        at sun.net.www.http.HttpClient.openServer(HttpClient.java:463)
        at sun.net.www.http.HttpClient.openServer(HttpClient.java:558)
        at sun.net.www.http.HttpClient.<init>(HttpClient.java:242)
        at sun.net.www.http.HttpClient.New(HttpClient.java:339)
        at sun.net.www.http.HttpClient.New(HttpClient.java:357)
        at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1220)
        at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1156)
        at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1050)
        at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:984)
        at no.finn.unleash.repository.HttpToggleFetcher.fetchToggles(HttpToggleFetcher.java:37)
        ... 8 common frames omitted

When we run web application in cygwin , has windows OS , its creating incorrect windows path with wrong slash using java client SDK

its throwing while creating repo file with /cygwin/ C/x/ff.json , this slash will not work in cygwin

Unable to detect failures in HttpToggleFetcher

The current API of Unleash/HttpToggleFetcher makes it difficult to detect if HttpToggleFetcher is actually able to fetch toggles or if it experiences for example network failures, authentication/authorization failures or simply 404s because because somebody shut down or moved the unleash server.

It would be nice if applications are able to observe such problems through the API.

Extend the unleash interface with context-data

In the current version of Unleash strategies needs to get their context data via special provides which typically is implemented as some magic-data available at the current request. This works well in most java-based web-applications.

However doing toggles in a standalone web-application this becomes much harder as you typically do not have a user bound to the current request. In this scenario you will typically have the context-data available runtime, at the same location you want to verify if a toggle should be on or of.

It would thus be beneficial if the client also could inject context data at runtime. The unleash API would then be overloaded with a new method, the the user can inject the required context-data.

unleash.isEnabled("app.someToggle", UnleashConext.of("k1", "v1", "k2", "v2"));

Unleash will then in turn inject the context-data to the strategy which would be extended to:

public interface Strategy {
    String getName();

    boolean isEnabled(Map<String, String> parameters);

    boolean isEnabled(Map<String, String> parameters, UnleashConext context);
}

(* if we move the client to java8 we could also provide a default implementation of the new method to avoid breaking the API)

This is also the approach used for the unleash-client-node.

Error fetching toggles from Unleash API (StatusCode: 304)

I have an Unleash server v3.2.1 and java client v3.2.0 on a SpringBoot 2 backend API.

Seems to work well and use the updated value on the backend API but in the console I have this warrning/error every second:

2019-02-18 15:26:20.592  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)
2019-02-18 15:26:21.865  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)
2019-02-18 15:26:22.745  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)
2019-02-18 15:26:23.789  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)
2019-02-18 15:26:23.842  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)
2019-02-18 15:26:24.375  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)
2019-02-18 15:26:25.008  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)
2019-02-18 15:26:26.282  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)
2019-02-18 15:26:26.990  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)
2019-02-18 15:26:27.315  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)
2019-02-18 15:26:27.992  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)
2019-02-18 15:26:28.161  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)
2019-02-18 15:26:29.079  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)
2019-02-18 15:26:29.201  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)
2019-02-18 15:26:30.279  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)
2019-02-18 15:26:30.593  WARN 7514 --- [sh-api-executor] n.f.u.r.FeatureToggleRepository          : Error fetching toggles from Unleash API (StatusCode: 304)

...

Can we make the API more explicit?

The way unleash is implemented now it is not really intuitive for the developer. Instantiating the unleash-client will also set up a background thread used to poll toggles and send metrics back to unleash. We see from time to time this ending up with memory leakage because the developer creates a new unleash instance per request handler.

Can we make the API more explicit by having dedicated methods for starting and stopping unleash?

  • unleash.startPolling()
  • unleash.destroy()

What should happen if the user has not stated unleash yet? Should we then just throw a runtime exception? Or always return false?

MetricsBucket is not thread safe (NullpointerException)

We sometimes get this exception:

java.lang.NullPointerException: null
    at no.finn.unleash.metric.MetricsBucket.registerCount(MetricsBucket.java:19)
    at no.finn.unleash.metric.UnleashMetricServiceImpl.count(UnleashMetricServiceImpl.java:43)
    at no.finn.unleash.DefaultUnleash.count(DefaultUnleash.java:138)
    at no.finn.unleash.DefaultUnleash.isEnabled(DefaultUnleash.java:85)

The issue seems to be that MetricsBucket is not thread safe. Changing the code to use a ConcurrentHashMap (using ConcurrentHashMap.computeIfAbsent in MetricsBucket.getOrCreate) would likely fix the problem

Create a unleash-mock-implementation to facilitate unit-testing

To allow users of the unleash-client to perform awesome unit-testing in their own application we must implement a simple UnleashMock client with a simple API.

I'm thinking of something like:

UnleashMock unleash = new UnleashMock();

//enable all feature toggles
unleash.enableAll()

//disable all feature toggles
unleash.disableAll()

//enable specific feature toggle(s)
unleash.enable("featureName")
unleash.enable("featureName", "toggle2", "...")

//disable specific feature toggle(s)
unleash.disable("featureName", "toggle2", "...")

client metrics

copied from Unleash/unleash#21

jarib:
There's currently no way of tracking what toggles are being used across applications. The simplest I can think of is to add easy statsd/graphite reporting in the client.

Perhaps look at Yammer Metrics. From reading the Kafka docs it sounds pretty nice:

Kafka uses Yammer Metrics for metrics reporting in both the server and the client. This can be configured to report stats using pluggable stats reporters to hook up to your monitoring system.

hennings:
Codahale Metrics (successor to Yammer metrics) is a nice library for timing
histograms, counters and gauges. There are several publishers you can plug
in to send the data to graphite, a servlet etc.

Henning
On 21 Oct 2014 15:33, "Jari Bakken" [email protected] wrote:

There's currently no way of tracking what toggles are being used across
applications. The simplest I can think of is to add easy statsd/graphite
reporting to the client.

Perhaps look at Yammer Metrics
https://dropwizard.github.io/metrics/3.1.0/. From reading the Kafka
docs it sounds pretty nice:

Kafka uses Yammer Metrics for metrics reporting in both the server and the
client. This can be configured to report stats using pluggable stats
reporters to hook up to your monitoring system.


Reply to this email directly or view it on GitHub
Unleash/unleash#21.

FeatureToggleRepository has set intialDelay to pooling interval

Now we have to wait a full polling interval before the client syncs feature toggle states with the server on start-up.

This can be significantly improved by just setting the initial delay to 0, forcing the client to perfom a server sync immediately.

Java client never fetches from server

I'm having trouble getting the Java client setup and running. Everything looks fine from the logs when running a simple test.

UnleashConfig config = UnleashConfig.builder()
				.appName("test")
				.instanceId("localhost")
				.unleashAPI("http://localhost:4242/api/")
				.build();
Unleash client = new DefaultUnleash(config);
assertTrue(client.isEnabled("test-feature"));

I'm running client v3.1.2 and server locally v3.1.7. I'm able to connect to the server fine using curl and also while running the node client. Both return expected results. The only logs I can see are

09:56:04.579 [main] INFO  no.finn.unleash.repository.ToggleBackupHandlerFile - Unleash will try to load feature toggle states from temporary backup
09:56:04.579 [main] INFO  no.finn.unleash.repository.ToggleBackupHandlerFile - Unleash will try to load feature toggle states from temporary backup
09:56:04.590 [main] WARN  no.finn.unleash.repository.ToggleBackupHandlerFile -  Unleash could not find the backup-file '/var/folders/nd/1c9btckx64jdxkj94j7dy8400000gn/T//unleash-test-repo.json'. 
This is expected behavior the first time unleash runs in a new environment.
09:56:04.590 [main] WARN  no.finn.unleash.repository.ToggleBackupHandlerFile -  Unleash could not find the backup-file '/var/folders/nd/1c9btckx64jdxkj94j7dy8400000gn/T//unleash-test-repo.json'. 
This is expected behavior the first time unleash runs in a new environment.

When I add a backup file and specify it in the builder then the last 2 log messages disappear however the result is still wrong. When I add the expected feature flag to the backup file then the above test passes so it seems like it's only fetching from the 'local backup' without ever going out to the server.

From the node client I get the following log on the server: New client registered with appName=ben-node-client and instanceId=ben-macbookpro which I never get from the Java client.

Any help would be greatly appreciated! I really like this project and would love to get it running.
Thanks

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.