problem: can notify client about new head before actual upstream made available

This commit is contained in:
Igor Artamonov
2019-07-30 00:21:31 -04:00
parent dd0c29c40c
commit 913ad6965a
6 changed files with 42 additions and 11 deletions

View File

@@ -4,6 +4,8 @@ import com.google.protobuf.ByteString
import io.emeraldpay.api.proto.BlockchainOuterClass import io.emeraldpay.api.proto.BlockchainOuterClass
import io.emeraldpay.api.proto.Common import io.emeraldpay.api.proto.Common
import io.emeraldpay.dshackle.upstream.AvailableChains import io.emeraldpay.dshackle.upstream.AvailableChains
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
import io.emeraldpay.dshackle.upstream.UpstreamServices
import io.emeraldpay.dshackle.upstream.Upstreams import io.emeraldpay.dshackle.upstream.Upstreams
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.domain.TransactionId import io.infinitape.etherjar.domain.TransactionId
@@ -16,6 +18,7 @@ import reactor.core.publisher.Mono
import reactor.core.publisher.TopicProcessor import reactor.core.publisher.TopicProcessor
import reactor.core.publisher.toFlux import reactor.core.publisher.toFlux
import java.lang.Exception import java.lang.Exception
import java.time.Duration
import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.ConcurrentLinkedQueue
import javax.annotation.PostConstruct import javax.annotation.PostConstruct
import kotlin.collections.HashMap import kotlin.collections.HashMap
@@ -56,10 +59,16 @@ class StreamHead(
private fun onBlock(chain: Chain, block: BlockJson<TransactionId>) { private fun onBlock(chain: Chain, block: BlockJson<TransactionId>) {
log.info("New block ${block.number} on ${chain.chainCode}") log.info("New block ${block.number} on ${chain.chainCode}")
clients[chain]!!.toFlux() upstreams.getUpstream(chain)?.let { up ->
.subscribe { stream -> UpstreamServices.onceOk(up).subscribe {avail ->
notify(chain, block, stream) if (avail) {
clients[chain]!!.toFlux()
.subscribe { stream ->
notify(chain, block, stream)
}
} }
}
}
} }
fun add(requestMono: Mono<Common.Chain>): Flux<BlockchainOuterClass.ChainHead> { fun add(requestMono: Mono<Common.Chain>): Flux<BlockchainOuterClass.ChainHead> {
@@ -78,8 +87,12 @@ class StreamHead(
fun notify(chain: Chain, client: TopicProcessor<BlockchainOuterClass.ChainHead>) { fun notify(chain: Chain, client: TopicProcessor<BlockchainOuterClass.ChainHead>) {
val upstream = upstreams.getUpstream(chain) ?: return val upstream = upstreams.getUpstream(chain) ?: return
val head = upstream.getHead().getHead() val head = upstream.getHead().getHead()
head.subscribe { head.subscribe { block ->
notify(chain, it, client) UpstreamServices.onceOk(upstream).subscribe { avail ->
if (avail) {
notify(chain, block, client)
}
}
} }
} }

View File

@@ -18,6 +18,9 @@ class ChainUpstreams (
init { init {
head = updateHead() head = updateHead()
observeStatus()
.distinctUntilChanged()
.subscribe { printStatus() }
} }
internal fun updateHead(): EthereumHead { internal fun updateHead(): EthereumHead {

View File

@@ -42,11 +42,9 @@ class EthereumRpcHead(
curr == null || curr.totalDifficulty < block.totalDifficulty curr == null || curr.totalDifficulty < block.totalDifficulty
} }
.subscribe { block -> .subscribe { block ->
head.set(block)
stream.onNext(block) stream.onNext(block)
} }
Flux.from(this.stream)
.subscribe { head.set(it) }
} }
override fun getHead(): Mono<BlockJson<TransactionId>> { override fun getHead(): Mono<BlockJson<TransactionId>> {

View File

@@ -32,10 +32,9 @@ class EthereumWs(
return return
} }
client.onNewBlock { client.onNewBlock {
head.set(it)
topic.onNext(it) topic.onNext(it)
} }
getFlux().subscribe { head.set(it) }
} }
fun getFlux(): Flux<BlockJson<TransactionId>> { fun getFlux(): Flux<BlockJson<TransactionId>> {

View File

@@ -89,9 +89,9 @@ open class GrpcUpstream(
} }
.subscribe { block -> .subscribe { block ->
log.debug("New block ${block.number} on ${chain}") log.debug("New block ${block.number} on ${chain}")
setStatus(UpstreamAvailability.OK)
headBlock.set(block) headBlock.set(block)
streamBlocks.onNext(block) streamBlocks.onNext(block)
setStatus(UpstreamAvailability.OK)
} }
} }

View File

@@ -0,0 +1,18 @@
package io.emeraldpay.dshackle.upstream
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import java.time.Duration
class UpstreamServices {
companion object {
fun onceOk(up: Upstream, waitTime: Duration = Duration.ofSeconds(15)): Mono<Boolean> {
return Flux.concat(Flux.just(up.getStatus()), up.observeStatus())
.timeout(waitTime, Mono.just(UpstreamAvailability.UNAVAILABLE))
.filter { it == UpstreamAvailability.OK }
.next()
.hasElement()
}
}
}