Fix status during launch, prevent recreating lagObservers (#299)

This commit is contained in:
KirillPamPam
2023-09-18 12:33:10 +04:00
committed by GitHub
parent bfdbce2743
commit 2ac566b09f
9 changed files with 56 additions and 12 deletions

View File

@@ -14,6 +14,7 @@ import org.springframework.cloud.sleuth.Tracer
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Configuration
import reactor.core.scheduler.Scheduler import reactor.core.scheduler.Scheduler
import java.util.concurrent.CopyOnWriteArrayList
@Configuration @Configuration
open class MultistreamsConfig(val beanFactory: ConfigurableListableBeanFactory) { open class MultistreamsConfig(val beanFactory: ConfigurableListableBeanFactory) {
@@ -46,7 +47,7 @@ open class MultistreamsConfig(val beanFactory: ConfigurableListableBeanFactory)
return EthereumMultistream( return EthereumMultistream(
chain, chain,
ArrayList(), CopyOnWriteArrayList(),
cachesFactory.getCaches(chain), cachesFactory.getCaches(chain),
headScheduler, headScheduler,
tracer tracer
@@ -63,7 +64,7 @@ open class MultistreamsConfig(val beanFactory: ConfigurableListableBeanFactory)
return EthereumPosMultiStream( return EthereumPosMultiStream(
chain, chain,
ArrayList(), CopyOnWriteArrayList(),
cachesFactory.getCaches(chain), cachesFactory.getCaches(chain),
headScheduler, headScheduler,
tracer tracer

View File

@@ -245,7 +245,10 @@ open class ConfiguredUpstreams(
eventPublisher eventPublisher
) )
upstream.start() upstream.start()
if (!upstream.isRunning) return null if (!upstream.isRunning) {
log.debug("Upstream ${upstream.getId()} is not running, it can't be added")
return null
}
return upstream return upstream
} }

View File

@@ -66,4 +66,8 @@ class UpstreamChangeEvent(
upstream.setCaches(caches) upstream.setCaches(caches)
} }
} }
override fun toString(): String {
return "UpstreamChangeEvent(chain=$chain, upstream=${upstream.getId()}, type=$type)"
}
} }

View File

@@ -89,11 +89,9 @@ abstract class DefaultUpstream(
} }
private fun statusByLag(lag: Long?, proposed: UpstreamAvailability): UpstreamAvailability { private fun statusByLag(lag: Long?, proposed: UpstreamAvailability): UpstreamAvailability {
if (lag == null) {
return UpstreamAvailability.UNAVAILABLE
}
return if (proposed == UpstreamAvailability.OK) { return if (proposed == UpstreamAvailability.OK) {
when { when {
lag == null -> proposed
lag > chainConfig.syncingLagSize -> UpstreamAvailability.SYNCING lag > chainConfig.syncingLagSize -> UpstreamAvailability.SYNCING
lag > chainConfig.laggingLagSize -> UpstreamAvailability.LAGGING lag > chainConfig.laggingLagSize -> UpstreamAvailability.LAGGING
else -> proposed else -> proposed

View File

@@ -62,11 +62,14 @@ abstract class HeadLagObserver(
.sample(throttling) .sample(throttling)
.flatMap(this::probeFollowers) .flatMap(this::probeFollowers)
.map { item -> .map { item ->
log.debug("Set lag ${item.t1} to upstream ${item.t2.getId()}")
item.t2.setLag(item.t1) item.t2.setLag(item.t1)
} }
} }
fun probeFollowers(top: BlockContainer): Flux<Tuple2<Long, Upstream>> { fun probeFollowers(top: BlockContainer): Flux<Tuple2<Long, Upstream>> {
log.debug("Compute lag for ${followers.map { it.getId() }}")
return Flux.fromIterable(followers) return Flux.fromIterable(followers)
.parallel(followers.size) .parallel(followers.size)
.flatMap { up -> mapLagging(top, up, getCurrentBlocks(up)).subscribeOn(lagObserverScheduler) } .flatMap { up -> mapLagging(top, up, getCurrentBlocks(up)).subscribeOn(lagObserverScheduler) }
@@ -87,6 +90,9 @@ abstract class HeadLagObserver(
.doOnError { t -> .doOnError { t ->
log.warn("Failed to find distance for $up", t) log.warn("Failed to find distance for $up", t)
} }
.doOnNext {
log.debug("Lag for ${it.t2.getId()} is ${it.t1}")
}
} }
open fun extractDistance(top: BlockContainer, curr: BlockContainer): Long { open fun extractDistance(top: BlockContainer, curr: BlockContainer): Long {

View File

@@ -219,11 +219,13 @@ abstract class Multistream(
} }
} }
} }
lagObserver?.stop()
lagObserver = null
when { when {
upstreams.size == 1 -> upstreams[0].setLag(0) upstreams.size == 1 -> {
upstreams.size > 1 -> lagObserver = makeLagObserver() lagObserver?.stop()
lagObserver = null
upstreams[0].setLag(0)
}
upstreams.size > 1 -> if (lagObserver == null) lagObserver = makeLagObserver()
} }
} }
} }
@@ -387,6 +389,7 @@ abstract class Multistream(
val chain = event.chain val chain = event.chain
if (this.chain == chain) { if (this.chain == chain) {
eventLock.withLock { eventLock.withLock {
log.debug("Processing event $event")
when (event.type) { when (event.type) {
UpstreamChangeEvent.ChangeType.REVALIDATED -> {} UpstreamChangeEvent.ChangeType.REVALIDATED -> {}
UpstreamChangeEvent.ChangeType.UPDATED -> { UpstreamChangeEvent.ChangeType.UPDATED -> {

View File

@@ -64,7 +64,10 @@ open class EthereumUpstreamValidator @JvmOverloads constructor(
) )
.map(::resolve) .map(::resolve)
.defaultIfEmpty(UpstreamAvailability.UNAVAILABLE) .defaultIfEmpty(UpstreamAvailability.UNAVAILABLE)
.onErrorReturn(UpstreamAvailability.UNAVAILABLE) .onErrorResume {
log.error("Error during upstream validation for ${upstream.getId()}", it)
Mono.just(UpstreamAvailability.UNAVAILABLE)
}
} }
fun resolve(results: Tuple2<UpstreamAvailability, UpstreamAvailability>): UpstreamAvailability { fun resolve(results: Tuple2<UpstreamAvailability, UpstreamAvailability>): UpstreamAvailability {
@@ -132,6 +135,9 @@ open class EthereumUpstreamValidator @JvmOverloads constructor(
.flatMap { .flatMap {
validate() validate()
} }
.doOnNext {
log.debug("Status after validation is $it for ${upstream.getId()}")
}
} }
fun validateUpstreamSettings(): Boolean { fun validateUpstreamSettings(): Boolean {

View File

@@ -107,7 +107,7 @@ open class EthereumPosMultiStream(
} }
override fun makeLagObserver(): HeadLagObserver = override fun makeLagObserver(): HeadLagObserver =
EthereumPosHeadLagObserver(head, ArrayList(upstreams), headScheduler).apply { EthereumPosHeadLagObserver(head, upstreams, headScheduler).apply {
start() start()
} }

View File

@@ -306,6 +306,29 @@ class MultistreamSpec extends Specification {
.verify(Duration.ofSeconds(3)) .verify(Duration.ofSeconds(3))
} }
def "After removing upstreams lag observer is stopped"() {
setup:
def up1 = TestingCommons.upstream("test-1", "internal")
def up2 = TestingCommons.upstream("test-2", "external")
def up3 = TestingCommons.upstream("test-3", "external")
def multistream = new EthereumPosMultiStream(Chain.ETHEREUM__MAINNET, [up1, up2, up3], Caches.default(), Schedulers.boundedElastic(), TestingCommons.tracerMock())
def observer = multistream.lagObserver
multistream.onUpstreamsUpdated()
expect:
multistream.getAll().size() == 3
observer.isRunning()
multistream.getAll().with {
remove(0)
remove(1)
}
multistream.getAll().size() == 1
multistream.onUpstreamsUpdated()
!observer.isRunning()
multistream.lagObserver == null
}
private BlockchainOuterClass.ChainStatus status(Common.AvailabilityEnum status) { private BlockchainOuterClass.ChainStatus status(Common.AvailabilityEnum status) {
return BlockchainOuterClass.ChainStatus.newBuilder() return BlockchainOuterClass.ChainStatus.newBuilder()
.setAvailability(status) .setAvailability(status)