Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load balancer throwing several exceptions when refreshing available sockets #786

Closed
PMacho opened this issue Apr 18, 2020 · 17 comments
Closed
Labels
bug superseded Issue is superseded by another
Projects
Milestone

Comments

@PMacho
Copy link
Contributor

PMacho commented Apr 18, 2020

I wanted to use the LoadBalancedRSocketMono in combination with springs ReactiveDiscoveryClient, but this doesn't work well at present.

The behaviour can be simulated by added the following to LoadBalancedRSocketMonoTest:

@Test
public void refreshSocketsTest() {
    LoadBalancedRSocketMono refreshingLoadBalancedRSocketMono = Flux
            .interval(Duration.ZERO, Duration.ofMillis(10))
            .doOnEach(System.out::println)
            .flatMap(i -> getSuppliers().collectList())
            .as(LoadBalancedRSocketMono::create);

    Flux
            .range(0, 1000)
            .flatMap(i -> refreshingLoadBalancedRSocketMono)
            .delayUntil(rSocket -> Flux
                    .interval(Duration.ZERO, Duration.ofMillis(1))
                    .filter(i -> rSocket.availability() > 0.0)
                    .next()
            )
            .flatMap(rSocket -> rSocket.requestResponse(
                    DefaultPayload.create("Hello from refreshing load balanced RSocket"))
            )
            .doOnNext(next -> System.out.println(Objects.requireNonNull(next.getDataUtf8())))
            .blockLast();
}

private Flux<RSocketSupplier> getSuppliers() {
    return Flux
            .fromIterable(Arrays.asList(1, 2, 3))
            .map(serviceId -> new RSocketSupplier(() -> Mono
                    .delay(Duration.ofSeconds(1))
                    .as(longMono -> Mono.just(new TestingRSocket(a ->
                            DefaultPayload.create(a.getDataUtf8() + " number " + serviceId)
                    )))
            ));
}

This test basically works, however from time to time it throws two different exceptions:

Index 2 out of bounds for length 2
java.lang.IndexOutOfBoundsException: Index 2 out of bounds for length 2
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
at java.base/java.util.Objects.checkIndex(Objects.java:372)
at java.base/java.util.ArrayList.get(ArrayList.java:458)
at io.rsocket.client.LoadBalancedRSocketMono.select(LoadBalancedRSocketMono.java:399)
at reactor.core.publisher.MonoSupplier.subscribe(MonoSupplier.java:56)
at io.rsocket.client.LoadBalancedRSocketMono$2.subscribe(LoadBalancedRSocketMono.java:231)
at reactor.core.publisher.Mono.subscribe(Mono.java:4210)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:418)
at reactor.core.publisher.FluxRange$RangeSubscription.slowPath(FluxRange.java:154)
at reactor.core.publisher.FluxRange$RangeSubscription.request(FluxRange.java:109)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onSubscribe(FluxFlatMap.java:363)
at reactor.core.publisher.FluxRange.subscribe(FluxRange.java:68)
at reactor.core.publisher.Flux.subscribe(Flux.java:8264)
at reactor.core.publisher.Flux.blockLast(Flux.java:2484)
at io.rsocket.client.LoadBalancedRSocketMonoTest.refreshSocketsTest(LoadBalancedRSocketMonoTest.java:124)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:40)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80)
at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:71)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at com.sun.proxy.$Proxy2.stop(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:412)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.base/java.lang.Thread.run(Thread.java:834)
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:99)
at reactor.core.publisher.Flux.blockLast(Flux.java:2485)
... 67 more

java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996)
at io.rsocket.client.LoadBalancedRSocketMono.refreshAperture(LoadBalancedRSocketMono.java:295)
at io.rsocket.client.LoadBalancedRSocketMono.refreshSockets(LoadBalancedRSocketMono.java:241)
at io.rsocket.client.LoadBalancedRSocketMono.select(LoadBalancedRSocketMono.java:377)
at reactor.core.publisher.MonoSupplier.subscribe(MonoSupplier.java:56)
at io.rsocket.client.LoadBalancedRSocketMono$2.subscribe(LoadBalancedRSocketMono.java:231)
at reactor.core.publisher.Mono.subscribe(Mono.java:4210)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:418)
at reactor.core.publisher.FluxRange$RangeSubscription.slowPath(FluxRange.java:154)
at reactor.core.publisher.FluxRange$RangeSubscription.request(FluxRange.java:109)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onSubscribe(FluxFlatMap.java:363)
at reactor.core.publisher.FluxRange.subscribe(FluxRange.java:68)
at reactor.core.publisher.Flux.subscribe(Flux.java:8264)
at reactor.core.publisher.Flux.blockLast(Flux.java:2484)
at io.rsocket.client.LoadBalancedRSocketMonoTest.refreshSocketsTest(LoadBalancedRSocketMonoTest.java:121)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:40)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80)
at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:71)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at com.sun.proxy.$Proxy2.stop(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:412)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.base/java.lang.Thread.run(Thread.java:834)
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:99)
at reactor.core.publisher.Flux.blockLast(Flux.java:2485)
... 67 more

@PMacho
Copy link
Contributor Author

PMacho commented Apr 18, 2020

I think the issue is related to the warning in https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

@OlegDokuka
Copy link
Member

OlegDokuka commented Apr 18, 2020

Hi @PMacho!

Thanks for letting us know!
This is known issue and basically is a duplicate of #716 (or at least looks pretty similar to the mentioned one)

We will be reworking Loadbalanced RSocket for 1.1 release.
Please stay tuned and we will let you know about the updates as soon as possible!

Cheers,
Oleh

@PMacho
Copy link
Contributor Author

PMacho commented Apr 18, 2020

Hi @OlegDokuka,

I actually don't think, it is the same issue. In #716 the point is that no renewal happens at all (which, if I should guess, is probably related to Flux.fromStream(...)). However in my case the availableSockers list apparently is updating. It is just that there are race conditions within this process.

As I mentioned already this is probably related to the List availableSockets, where sockets are removed and added within the constructor of WeightedSocket. This is (according to https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html) not a thread safe operation and could thus lead to the strange Exceptions I saw.

I could help solving this issue, if you are interested.

Best, Peter

@OlegDokuka
Copy link
Member

OlegDokuka commented Apr 18, 2020

@PMacho PRs are welcome.

In general, all the open issues related to LoadBalancedRSocket has the same root-cause - improper implementation and improper concurrency handling.

Please keep in mind that the LoadBalancedRSocket will be rewritten from scratch. Since it is the implementation of Reactor's Mono it has lots of pitfalls related to concurrency and right now the existing version is far from how it should be properly implemented.

However, please do not give up and try to fix your findings and send your proposal!

Cheers,
Oleh

@PMacho
Copy link
Contributor Author

PMacho commented Apr 18, 2020

@OlegDokuka yeah, honestly I didn't want to say it that way, but yes I also think so. The WeightedSocket has great ideas inside, but the handlings needs a basic rewrite, strictly following the lines of reactor.
I'll try to find time to write down some ideas in code.

@OlegDokuka
Copy link
Member

Also, you may find useful this PR from which you may take some ideas #685

@PMacho
Copy link
Contributor Author

PMacho commented Apr 18, 2020

Thank you, I'll have a look at it.

@PMacho
Copy link
Contributor Author

PMacho commented May 17, 2020

@OlegDokuka

Hi,

I did some work, trying to make the socket pooling/selection reactive (without synchronized methods). An unordered snapshot can be viewed on my github page, the main entry point is LoadBalancedRSocket.

I however came across quite some issues. I'd like to have a bit of discussion with someone before investigating too much time into things, that might not be accepted later. (I am quite new on github and do not really know the normal workflow.)

My questions include but are not limited to:

  1. The CoutingSubscribers pending streams is not even used anywhere
  2. Is it really a good approach to make the amount of active sockets elastic? At the moment my reimplementation is just static with respect to the activeSockets size (but can be extended to elastic behaviour). The official implementation (the updating aperture) however only depends on the request response model.
  3. I generally doubt it makes much sense to use statistical values depending on the request-response time to calculate the availability of sockets. This only makes sense if all requests are equal, which (I think) is not realistic in a real world example. Such an approach would be useful if it would measure the low-level data transmission by means of TCP packages or similar. Alternatively, one could send standard requests like simple pings to have a better measure. However, I suggest to use the total amount of pending requests (especially with respect to point 1.), instead of the execution time.
  4. I think there should be the possibility to choose the load balancing strategy, quite similar to Schedulers in reactive streams. Finally the developer knows the situation better and can elaborate which strategy to use. A possible implementation of this can also be seen in my fork of your project. At the moments there is RoundRobinRSocketPool and WeightedRSocketPool, both based on abstract RSocketPool.

Note: In case you want to have a look at my fork, I am not done and I didn't investigate into testing yet.

@OlegDokuka
Copy link
Member

@PMacho

Hey. I also started to reimplement LoadbalancingRSocket on my own. if you wish we can have a call and discuss all these questions

@PMacho
Copy link
Contributor Author

PMacho commented May 17, 2020

Ok we definitely should. Otherwise, we’ll do the work twice. How can I reach you?

@OlegDokuka
Copy link
Member

Please drop me a message at https://twitter.com/OlehDokuka

@PaoloTheKillah
Copy link

@OlegDokuka at my current job we were studying the possibility of adding the load balancer to our code (it provides useful features that we would like to use) but we stopped due mostly to the issue reported in issue #713
Since I am reading here that there is a rewrite ongoing for the load balancer I would like to ask:

  • Do you have an idea when the new loadbalancer version will be available?
  • If you need help with the current rewriting effort I can contribute. Can you point me to where the new code is being developed and how I can help?

Cheers,
Paolo

@OlegDokuka
Copy link
Member

@PaoloTheKillah We are planning to have a 1.1-M1 release on the 1st of August. In the good case, rework related to loadbalancer will go in that release. In the worse case - it is going to be M2 which is planned on the beginning of September

@PaoloTheKillah
Copy link

@OlegDokuka that's great news! thanks for the prompt response :)

@OlegDokuka OlegDokuka added this to the 1.1 M2 milestone Aug 12, 2020
@OlegDokuka
Copy link
Member

@PMacho we have finally introduced new implementation.

Would you like to play with it and see whether it has to be improved?

@PMacho
Copy link
Contributor Author

PMacho commented Aug 13, 2020

Hi @OlegDokuka, nice to jetzt from you. I'll sure look at the new implementation as soon as possible and send a feedback.

@OlegDokuka OlegDokuka modified the milestones: 1.1 M2, 1.1 RC1 Sep 14, 2020
@rstoyanchev rstoyanchev modified the milestones: 1.1 RC1, 1.1.0 Oct 12, 2020
@OlegDokuka
Copy link
Member

should be closed by #953

@OlegDokuka OlegDokuka added this to Done in Addons Oct 27, 2020
@OlegDokuka OlegDokuka added the superseded Issue is superseded by another label Oct 27, 2020
@OlegDokuka OlegDokuka removed this from the 1.1.0 milestone Oct 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug superseded Issue is superseded by another
Projects
Addons
  
Done
Development

No branches or pull requests

4 participants