unleash / unleash-client-java Goto Github PK
View Code? Open in Web Editor NEWUnleash client SDK for Java
Home Page: https://docs.getunleash.io
License: Apache License 2.0
Unleash client SDK for Java
Home Page: https://docs.getunleash.io
License: Apache License 2.0
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
How to reproduce:
/tmp/unleash-repo.json
is empty or invalid json.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)
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/:?]
Travis has jdk support for openjdk11. Also need to touch the pom-file to specify jdk11.
Wanted outcome:
Travis build with jdk8 and jdk11.
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?
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.
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.
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)
As specified in https://github.com/Unleash/unleash/blob/master/docs/api/client/register-api.md clients should now include sdk type and version identifier.
The value of the of this field should be picked up from pom.xml and look like:
sdkVersion: unleash-client-java:3.x.z
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?
See Unleash/unleash-client-go#60 for details
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.:
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!
Create tests and make sure the client acts well if the api is behaving bad.
Situations that might occur is malformed json, empty results etc.
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 requestupdate
- Unleash client got updated toggle configuration from server.error
- Unleash client failed fetching data from unleash-server (might want to set some retry limit?).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?
The project's log4j dependency is known to be vulnerable. Further details here: https://www.cvedetails.com/cve/CVE-2017-5645/
public interface Unleash {
...
boolean isEnabled(String toggleName, Map<String,String> parameters);
...
}
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.
The client should log if it gets 400 errors from the server.
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?
see Unleash/unleash#247 for details.
Pick a widely adopted standard supported by major java-IDEs (intellij, eclipse, visual studio) and define the rules for this project. This makes it easier for outsiders to contribute!
Options:
Others we should consider?
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.
The next version of Unleash has changed the API endpoint for the client calls. Next version of the client should use the client path.
https://github.com/Unleash/unleash/tree/master/docs/api/client
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);
}
access Unleash API over https using unleash-client having self signed certificate
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.
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:
Finn client has the following strategies:
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.
This issue relates to support the new API-format suggested in Unleash/unleash#102
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
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.
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.
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)
...
Create tests for JsonFeatureToggleParser making sure it handles corner cases. Invalid json, no data, random data etc.
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?
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
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", "...")
To be able to try it and see how it work, it would be great to be able to just run it with out needing to set up the database.
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.
Mostly to support local development we should add appName to the local toggles-backup-file to avoid collisions when /if a user runs different apps using unleash.
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.
PR #192 in innfinn is a great example on how it's done. We should have something like that here on github in our documentation/test code.
Improve upon https://github.com/finn-no/unleash-client-java/tree/master/src/test/java/no/finn/unleash/example , and maybe link to it in the readme?
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
See if it provides any value to switch.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.