problem: native calls are execute one by one, and possibly exhausting target upstream
This commit is contained in:
@@ -17,6 +17,7 @@ import reactor.core.publisher.toMono
|
|||||||
import reactor.util.function.Tuple2
|
import reactor.util.function.Tuple2
|
||||||
import reactor.util.function.Tuples
|
import reactor.util.function.Tuples
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
|
import java.time.Duration
|
||||||
import java.util.function.Predicate
|
import java.util.function.Predicate
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -30,7 +31,9 @@ class NativeCall(
|
|||||||
open fun nativeCall(requestMono: Mono<BlockchainOuterClass.NativeCallRequest>): Flux<BlockchainOuterClass.NativeCallReplyItem> {
|
open fun nativeCall(requestMono: Mono<BlockchainOuterClass.NativeCallRequest>): Flux<BlockchainOuterClass.NativeCallReplyItem> {
|
||||||
return requestMono.flatMapMany(this::prepareCall)
|
return requestMono.flatMapMany(this::prepareCall)
|
||||||
.map(this::setupCallParams)
|
.map(this::setupCallParams)
|
||||||
|
.parallel()
|
||||||
.flatMap(this::executeOnRemote)
|
.flatMap(this::executeOnRemote)
|
||||||
|
.sequential()
|
||||||
.map(this::buildResponse)
|
.map(this::buildResponse)
|
||||||
.doOnError { e -> log.warn("Error during native call", e) }
|
.doOnError { e -> log.warn("Error during native call", e) }
|
||||||
.onErrorResume(this::processException)
|
.onErrorResume(this::processException)
|
||||||
@@ -89,7 +92,11 @@ class NativeCall(
|
|||||||
|
|
||||||
fun executeOnRemote(ctx: CallContext<Tuple2<String, List<Any>>>): Mono<CallContext<ByteArray>> {
|
fun executeOnRemote(ctx: CallContext<Tuple2<String, List<Any>>>): Mono<CallContext<ByteArray>> {
|
||||||
val p: Predicate<Any> = CallQuorum.untilResolved(ctx.callQuorum)
|
val p: Predicate<Any> = CallQuorum.untilResolved(ctx.callQuorum)
|
||||||
return ctx.apis.toFlux()
|
val all = ctx.apis.toFlux().share()
|
||||||
|
//execute on the first API immediately, and then make a delay between each call to not dos upstreams
|
||||||
|
val immediate = Flux.from(all).take(1)
|
||||||
|
val retries = Flux.from(all).delayElements(Duration.ofMillis(200))
|
||||||
|
return Flux.concat(immediate, retries)
|
||||||
.takeWhile(p)
|
.takeWhile(p)
|
||||||
.flatMap { api ->
|
.flatMap { api ->
|
||||||
api.execute(ctx.id, ctx.payload.t1, ctx.payload.t2).map { Tuples.of(it, api.upstream!!) }
|
api.execute(ctx.id, ctx.payload.t1, ctx.payload.t2).map { Tuples.of(it, api.upstream!!) }
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class EthereumGrpcTransportSpec extends Specification {
|
|||||||
|
|
||||||
then:
|
then:
|
||||||
1 * otherSideUpstreams.getUpstream(Chain.ETHEREUM) >> otherSideAggr
|
1 * otherSideUpstreams.getUpstream(Chain.ETHEREUM) >> otherSideAggr
|
||||||
1 * otherSideAggr.getApis(_) >> [otherSideApi].multiply(3).iterator()
|
1 * otherSideAggr.getApis(_) >> [otherSideApi].multiply(34).iterator()
|
||||||
_ * otherSideAggr.getHead() >> Stub(EthereumHead)
|
_ * otherSideAggr.getHead() >> Stub(EthereumHead)
|
||||||
_ * otherSideAggr.getTargets() >> ethereumTargets
|
_ * otherSideAggr.getTargets() >> ethereumTargets
|
||||||
status.failed == 0
|
status.failed == 0
|
||||||
|
|||||||
Reference in New Issue
Block a user