launchdarkly/java-server-sdk

Please provide ability to `LDClient` in non-blocking manner

Closed this issue · 4 comments

Reading source code I found that new LDClient blocks calling thread until we connect to backend and fetch data.

Could you please provide something like LDClient.create: Future[LDClient] which does not block threads.

I'm not sure which part of the code you were looking at, but that's not quite accurate. Please look at LDClient.java:270 and you will see that it conditionally blocks if the startWait configuration property (described here) is greater than zero. If you have set startWait to zero, then the LDClient constructor is guaranteed to return immediately.

The advantage to doing it this way is that then you have an LDClient object which, even if it is not yet finished initializing, can be inspected to see its status, or to do other things like sending analytics events or setting listeners for notifications. If we returned a Future, then you would have no way to access the LDClient at all until it was finished.

Once you have that object, assuming you do want to wait at some point for client initialization (since trying to evaluate flags will fail if it has not yet acquired the flag data), the method for that is client.getDataSourceStatusProvider().waitFor().

Thanks!
startWait=0 should do the trick, however there after you still would need to use blocking waitFor(), is there anything better that supports asynchrony?

@t3hnar Currently there is not, but it's trivial in Java to spin a thread for such a task. One way to do that would look like this:

final CompletableFuture<Boolean> clientInitialization = new CompletableFuture<>();
new Thread(() -> {
  boolean result = client.getDataSourceStatusProvider()
    .waitFor(DataSourceStatusProvider.State.VALID, Duration.ZERO);
  clientInitialization.complete(result);
}).start();

There are two main reasons why we haven't implemented more asynchronous APIs in the Java SDK already. The main one is simply that we hadn't had any requests for them in the last two years (and prior to two years ago, we couldn't use most of the Future mechanisms anyway because we still had to maintain compatibility with Java 7). The closest we've had was a request to rewrite the whole SDK to use one specific reactive Java framework, which we're unlikely to do. And in a server-side context, it's unsurprising that a lot of application developers were fine with using synchronous semantics for this one-time action of initializing the SDK during startup... but everyone has their own use cases which are hard to anticipate.

The other is that, unlike other platforms where there is a standard way to do asynchronous tasks and/or to manage thread pools, Java provides the building blocks but leaves a lot of leeway as to how you want those things to work, and it is tricky for library code to anticipate what will make sense for the application calling it. For instance, any caller who receives a Future can configure it with CompletionStage callbacks that could execute either on another worker thread or on the same thread that called complete on the Future, and the latter would be one of the SDK's core processing threads, which would be undesirable. That might still be a risk we decide is worthwhile with adequate documentation, but it does mean that some extra thought needs to go into the API design.

Thanks for an example and comprehensive reply :)

For us async api would be preferable as well as ability to control both CPU intensive and blocking ops thread pools to be used by the client.

Not a blocker though…